Bondo416さんのAtCoder Beginner Contest 212での成績:743位
— ボンド@競プロ (@bond_cmprog) July 31, 2021
パフォーマンス:1611相当
レーティング:1480→1494 (+14) :)#AtCoder #ABC212 https://t.co/ieEPHZKYUQ
A - Alloy
問題文の条件を判定する
提出コード
void solve(){ int A, B; cin >> A >> B; if(0 < A and B == 0) cout << "Gold" << endl; else if(A == 0 and 0 < B) cout << "Silver" << endl; else cout << "Alloy" << endl; }
B - Weak Password
弱い条件を満たさなければ Strong
そうでなければ Weak
提出コード
void solve(){ string A; cin >> A; if(A[0] == A[1] and A[1] == A[2] and A[2] == A[3]){ cout << "Weak" << endl; return; } bool weak = true; REP(i,3){ if(A[i] == '9'){ if(A[i+1] != '0'){ weak = false; } } else if((A[i] - '0' + 1) != (A[i+1] - '0')) weak = false; } cout << (weak ? "Weak" : "Strong") << endl; }
C - Min Difference
$ A_i $ を固定したとき、$ B $ の要素で $ A_i $ に近いものを調べればいい
$ B $ を予めソートしておきlower_boundで求めた値を $ B_j $ とすると、$ B _j $ を含めた前後の値を実際に計算しその最小値を求めればいい
提出コード
void solve(){ int N, M; cin >> N >> M; vector<ll> A(N), B(M); REP(i,N) cin >> A[i]; REP(i,M) cin >> B[i]; sort(A.begin(), A.end()); sort(B.begin(), B.end()); ll ans = LINF; REP(i,N){ int idx = lower_bound(B.begin(), B.end(), A[i]) - B.begin(); if(idx < M) chmin(ans, abs(A[i] - B[idx])); if(idx + 1 < M) chmin(ans, abs(A[i] - B[idx+1])); if(idx - 1 >= 0) chmin(ans, abs(A[i] - B[idx-1])); } cout << ans << endl; }
D - Querying Multiset
$ i $ 番目のクエリまでに加算された $ X_i $ の総和を $ sum_i $ とする
$ i $ 番目のクエリのときに $ j $ 番目に追加された $ X_j $ を取り出したときの値は $ X_j + sum_i - sum_j $ となる
実際の実装では $ sum $ を 今までの累積和 $ sum_i $ として持っておき、追加するときにその時点での累積和( $ sum_j $ )を $ X_j $ から引いておき、出力する際に $ sum ( = sum_i ) $ を加算することで上記と同様のことができる
提出コード
void solve(){ int Q; cin >> Q; ll sum = 0; map<ll, ll> mp; while(Q--){ int q; ll X; cin >> q; if(q == 1){ cin >> X; mp[X-sum]++; } else if(q == 2){ cin >> X; sum += X; } else{ ll num = mp.begin() -> first; cout << num + sum << endl; mp[num]--; if(mp[num] == 0) mp.erase(num); } } }
E - Safety Journey
$ dp[i][j] := i $ 日目に都市 $ j $ にいる相違なる旅の数としてDPをする
$ sum_i = \sum_{j=0}^{j=N-1} dp[i][j] $ とすると $ M = 0 $ の場合、$ dp[i+1][j] = sum_i - dp[i][j] $ となる
$ M \gt 0 $ の場合もほぼ同様で、都市 $ i $ と結ばれていない頂点 $ j $ の集合を考えると $ dp[i+1][j] = sum_i - dp[i][j] - \sum_{j} dp[i][j] $ となり全体で $ O(K(N+M)) $ となる
提出コード
void solve(){ int N, M, K; cin >> N >> M >> K; vector<int> U(M), V(M); REP(i,M){ cin >> U[i] >> V[i]; --U[i], --V[i]; } vector<mint> dp(N); dp[0] = 1; REP(_,K){ auto nxt = vector<mint>(N); mint sum = 0; REP(i,N) sum += dp[i]; REP(i,N) nxt[i] += sum - dp[i]; REP(i,M){ nxt[U[i]] -= dp[V[i]]; nxt[V[i]] -= dp[U[i]]; } swap(dp, nxt); } cout << dp[0] << endl; }
G - Power Pair
法 $ P $ の原始根を $ r $ とし、 $ 1 \leq a, b \leq P - 1 $ に対して $ x \equiv r^{a} , y \equiv r^b \pmod{P} $ とする
$ x^n \equiv y \pmod{P} $
$ \Leftrightarrow r^{an} \equiv r^b \pmod{P-1} $
$ \Leftrightarrow an \equiv b \pmod{P-1} $
となり、$ an \equiv b \pmod{P-1} $ を満たす正整数$ n $ が存在するような $ (a, b) $ を数えればいい
これは $ \sum_{a=1}^{P-1} \frac{P-1}{gcd(P-1, a)} $ で求められるが、$ O(P) $ となる
そのため $ g = gcd(P-1, a) $ となるような $ g $ を満たす $ a ( 1 \leq a \leq P - 1) $ の個数を $ f(g) $ とすると $ \sum _{g} \frac{P-1}{g} f(g) $ となる
$ g $ は $ P - 1 $ の約数であり、$ f(g) $ は $ P - 1 $ の約数の数 $ d $ に対し、$ O(d^2) $ で求められるので全体で $ O( \sqrt{P} + d^2 ) $ で求めることができる
提出コード
void solve(){ ll P; cin >> P; P--; vector<ll> div; for(ll i=1;i*i<=P;i++){ if(P % i == 0){ div.emplace_back(i); if(P != i * i) div.emplace_back(P / i); } } sort(div.rbegin(), div.rend()); int sz = div.size(); vector<ll> sum(sz); REP(i,sz){ sum[i] = P / div[i]; REP(j,i) if(div[j] % div[i] == 0) sum[i] -= sum[j]; } mint ans = 1; REP(i,sz) ans += mint(P / div[i]) * sum[i]; cout << ans << endl; }