본문 바로가기
PS/AtCoder

AtCoder ABC 266 풀이

by jaehoonChoi 2022. 8. 29.

https://atcoder.jp/contests/abc266/tasks

 

Tasks - AtCoder Beginner Contest 266

AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

atcoder.jp

 

A.

중간 글자를 출력하면 됩니다. 

#include<bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    string s; cin >> s;
    cout << s[s.size()/2];
}

 

 

B. 

우선 N이 p로 나눠진다면 답은 0입니다. 

이제 4경우로 나눠줍니다. 

1) N>p인 경우 답은 N%p 입니다. 

2) 0<N<p인 경우 답은 p-N입니다.

3)-p<N<0인 경우 답은 p+N입니다.

4) N<-p인 경우 답은 N-N%p입니다. 

 

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    ll n; cin >> n;
    if (n % mod == 0) {
        cout << 0;
    }
    else if (n >= mod) {
        cout << n % mod;
    }
    else if (n > 0 && n < mod) {
        cout << mod - n;
    }
    else if (n <= 0 && n >= -mod) {
        cout << mod + n;
    }
    else if (n < -mod) {
        n *= -1;
        cout << mod - (n % mod);
    }
}

 

 

C. 

네 점을 줄때 볼록사각형인지 출력하는 문제입니다. 

4개의 CCW가 같은 부호면 됩니다. 세 점 일직선등 엣지케이스가 없어 쉬운 문제입니다. 

 

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
#define x first
#define y second

int ccw(pll a, pll b, pll c) {
    ll t = (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x);
    return (t > 0) - (t < 0);
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    pll a, b, c, d;
    cin >> a.x >> a.y;
    cin >> b.x >> b.y;
    cin >> c.x >> c.y;
    cin >> d.x >> d.y;
    int mul = 1;
    mul *= ccw(a, b, c);
    mul *= ccw(b, c, d);
    mul *= ccw(c, d, a);
    mul *= ccw(d, a, b);
    cout << (mul == 1 ? "Yes" : "No");
}

 

 

 

D. 

dp[x][t]를 위치 x에 시간 t에 오는 경우 최댓값이라 정의합니다.

전이는 t-1에서 옵니다. 또한 x는 {x-1,x,x+1}에서 올 수 있습니다. 최대 1의 속도이므로 움직이지 않아도 

되는것에 유의합니다. 또한 dp[x][t]에서 점수 획득이 가능하다면 그 점수를 더해주면서 갱신하면 됩니다. 

dp[x][t]=max(dp[x-1][t-1], dp[x][t-1], dp[x+1][t-1])+C[x][t]가 됩니다. 

 

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll n, T;
ll dp[5][100005], c[5][100005];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        ll t, x, v;
        cin >> t >> x >> v;
        c[x][t] = v;
        if (i == n) T = t;
    }
    fill(&dp[0][0], &dp[4][T], -1e18);
    dp[0][0] = 0;
    for (int t = 1; t <= T; t++) {
        for (int x = 0; x < 5; x++) {
            dp[x][t] = dp[x][t - 1];
            if (x < 4) dp[x][t] = max(dp[x][t], dp[x + 1][t - 1]);
            if (x > 0) dp[x][t] = max(dp[x][t], dp[x - 1][t - 1]);
            dp[x][t] += c[x][t];
        }
    }
    ll ans = 0;
    for (int x = 0; x < 5; x++) {
        ans = max(ans, dp[x][T]);
    }
    cout << ans;
}

 

 

 

E.

dp[n]을 n번째 던질 때 점수의 기댓값이라 정의합니다. 

언제든 게임을 그만둘 수 있으므로, dp[n]보다 작은 값이 주사위에서 나오면 그만하면 됩니다.

따라서 매번 기댓값을 키울 수 있습니다. 

dp[n]=1/6*sigma(max(i,dp[n-1])) 임을 쉽게 알 수 있습니다. 

 

#include<bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    int n;  cin >> n;
    vector<double> dp(n + 1);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= 6; j++) {
            dp[i] += max(double(j), dp[i - 1]) / 6;
        }
    }
    cout<<fixed;
    cout.precision(8);
    cout << dp[n];
}

 

 

 

F. 

N개의 점에 N개의 변이 있습니다. 이러한 그래프는 트리에서 선분 1개를 추가하여 사이클이 만들어집니다. 

경로가 유일하려면 두 점이 모두 사이클에 도함되지 않으면 됩니다.  다만 예외적으로 사이클에 포함되는 점과

인접한 정점쌍까지는 가능합니다. 위상정렬을 하는 과정에서 사이클에 포함된 점들은 큐에 들어갈 수 없습니다.

따라서 위상정렬을 하면서 유니온파인드를 하고, 인접차수가 1이 된다면(양방향이므로 1일때 큐에 넣어야 함)

큐에 넣고 돌려주면 됩니다. 위상정렬에서 사이클을 찾을 때 성질을 사용하는 어려운 문제였습니다.

 

#include<bits/stdc++.h>
using namespace std;
int n, u, v, q, x, y;
vector<int>g[200005];
int par[200005], ind[200005];

int find(int x) {
    return !~par[x] ? x : par[x] = find(par[x]);
}

void uni(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) par[y] = x;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> u >> v;
        ind[u]++, ind[v]++;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    memset(par, -1, sizeof(par));
    queue<int>que;
    for (int i = 1; i <= n; i++) {
        if (ind[i] == 1) que.push(i);
    }
    while (que.size()) {
        int cur = que.front(); que.pop();
        for (int nxt : g[cur]) {
            if (--ind[nxt] == 1)que.push(nxt);
            uni(cur, nxt);
        }
    }
    cin >> q;
    while (q--) {
        cin >> x >> y;
        cout << (find(x) == find(y) ? "Yes" : "No") << '\n';
    }
}

 

 

 

G. 

아이디어성 문제입니다. R과 RG와 B를 먼저 칠한다고 가정합니다. 

그럼 R을 r-k개, RG를 k개, B를 b개 배치하는 경우의 수는 (r+b)!/(r-k)!k!b! 입니다. 

이제 G를 끼워넣어봅시다. 배치한 곳의 오른쪽에만 공간이 있다고 가정합니다. 

그럼 G는 R만 배치한 곳의 오른쪽에만 배치할 수 없고 나머지 공간에는 모두 배치할 수 있습니다. 

또한 미리 배치한 곳의 맨 앞에도 공간을 만들어 줍시다. (G가 맨앞에 배치되는 경우)

공간이 총 b+k+1개가 생깁니다. b+k+1개 공간에 중복을 허락하여 g-k개를 채우는 경우의 수는 

(b+k+1) H (g-k) = (b+g) C (g-k) 가 됩니다. 위와 곱해서 계산해주면 됩니다. 

곱하기 전에 식을 깔끔히 정리하면, gCk * b+gCg * b+rCr-k 가 됩니다.

 

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MAX = 1000011, mod= 998244353;
ll r, g, b, k, fac[2*MAX];

void make_table() {
    fac[0] = 1;
    fac[1] = 1;
    for (int i = 2; i < 2 * MAX; i++) {
        fac[i] = (i * fac[i - 1]) % mod;
    }
}

ll pow(ll a, ll b) {
    ll ret = 1;
    while (b) {
        if (b & 1) ret = (ret * a) % mod;
        a = (a * a) % mod;
        b /= 2;
    }
    return ret;
}

ll inv(ll x) {
    return pow(x, mod - 2);
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> r >> g >> b >> k;
    make_table();

    ll c1 = fac[g];
    c1 = (c1 * inv(fac[k])) % mod;
    c1 = (c1 * inv(fac[g - k])) % mod;

    ll c2 = fac[b + g];
    c2 = (c2 * inv(fac[b])) % mod;
    c2 = (c2 * inv(fac[g])) % mod;

    ll c3 = fac[b + r];
    c3 = (c3 * inv(fac[r - k])) % mod;
    c3 = (c3 * inv(fac[b + k])) % mod;

    ll ans = c1;
    ans = (ans * c2) % mod;
    ans = (ans * c3) % mod;

    cout << ans;
}

 

 

'PS > AtCoder' 카테고리의 다른 글

AtCoder ABC 261 풀이  (0) 2022.09.01
AtCoder ABC 262 풀이  (0) 2022.08.30
AtCoder ABC 263 풀이  (0) 2022.08.28
AtCoder ABC 264 풀이  (0) 2022.08.27
AtCoder ABC 265 풀이  (0) 2022.08.25

댓글