Bondo416さんのAtCoder Beginner Contest 199(Sponsored by Panasonic)での成績:1402位
— ボンド@競プロ (@bond_cmprog) April 24, 2021
パフォーマンス:1322相当
レーティング:1489→1474 (-15) :(#AtCoder #ABC199(SponsoredbyPanasonic) https://t.co/KtHup10OlP
A - Square Inequality
オーバーフローなどの心配もないので素直に判定をする
提出コード
void solve(){ ll A, B, C; cin >> A >> B >> C; if(A * A + B * B < C * C) cout << "Yes" << endl; else cout << "No" << endl; }
B - Intersection
最終的な答えは $ \max(A) \leq x \leq \min(B) $ を満たす $ x $ の個数なので $ \max(0, \min(B) - \max(A) + 1) $ が答え
提出コード
void solve(){ int N; cin >> N; vector<int> A(N), B(N); REP(i,N) cin >> A[i]; REP(i,N) cin >> B[i]; int a = 0, b = INF; REP(i,N){ chmax(a, A[i]); chmin(b, B[i]); } cout << max(0, b - a + 1) << endl; }
C - IPFL
愚直に文字列を作り直したりすると間に合わないので少し工夫する必要がある
今どっちが先頭なのかをflagなどで持っておくと、swapを行うだけでいいので十分に間に合う
提出コード
void solve(){ int N, Q; string S; cin >> N >> S >> Q; string s1 = S.substr(0, N); string s2 = S.substr(N, 2*N); int x = 0; REP(i,Q){ int t, a, b; cin >> t >> a >> b; --a, --b; // dumps(i, a, b, x); if(t == 1){ if(x == 0){ if(a < N and b < N) swap(s1[a], s1[b]); else if(a < N and b >= N) swap(s1[a], s2[b-N]); else swap(s2[a-N], s2[b-N]); } else{ if(a < N and b < N){ swap(s2[a], s2[b]); } else if(a < N and b >= N){ swap(s2[a], s1[b-N]); } else{ swap(s1[a-N], s1[b-N]); } } } else{ x = 1 - x; } } if(x) cout << s2 << s1 << endl; else cout << s1 << s2 << endl; }
D - RGB Coloring 2
どの頂点をどの色で塗るかを全探索をすると$ \mathcal{O}(3^N) $ となり間に合わない
どの頂点を赤色で塗り、他の頂点を青と緑色で塗るかを考える
そうすると、赤色で塗った頂点以外の各連結成分が二部グラフになっていればよくその場合の数を数えればいい
そのため、どの頂点を赤色で塗るかをbit全探索をし、各連結成分ごとに二部グラフになっているかを判定する
二部グラフを満たす場合、グラフ全体の連結成分の個数を $ sz $、赤色で塗った頂点の個数を $ cnt $ とすると $ 2 ^ {sz - cnt} $ 通り答えに加算する
実際の実装では二部グラフ判定のために頂点数を拡張しているので $ 2 ^ {\frac{sz}{2} - cnt} $ となる
提出コード
void solve(){ int N, M; cin >> N >> M; vector<int> edge(N); REP(i,M){ int a, b; cin >> a >> b; --a, --b; edge[a] |= (1 << b); edge[b] |= (1 << a); } ll ans = 0; REP(i,1<<N){ int cnt = 0; bool ok = true; REP(j,N) if(i >> j & 1){ if(i & edge[j]) ok = false; cnt++; } if(!ok) continue; UnionFind uf(2*N); int sz = 2 * N; REP(j,N) if(!(i >> j & 1)){ for(int k=j+1;k<N;k++){ if((edge[j] >> k & 1) and !((i >> k & 1))){ if(uf.unite(j, k + N)) sz--; if(uf.unite(k, j + N)) sz--; } } } REP(i,N) if(uf.issame(i, i + N)) ok = false; if(ok) ans += 1 << (sz / 2 - cnt); } cout << ans << endl; }
E - Permutation
$ dp[state] := $ すでに選んだ整数の状態が $ state $ かつ $ X_i \leq |state| $ であるような条件を満たしているときの場合の数としてbitDPを行う
$ x \notin state $ を満たす整数 $ x $ を追加する時、$ X_i = |state \cap x | $ を満たす $ i $ について、$ state \cap x $ に含まれる $ Y_i $ 以下の整数が $ Z_i $ 以下の場合DPの遷移が可能となる
そのため、上記の条件を満たすようなDP遷移を行ったときの $ dp[2^N -1 ] $ が最終的な答えとなる
提出コード
void solve(){ int N, M; cin >> N >> M; vector<int> X(M), Y(M), Z(M); REP(i,M) cin >> X[i] >> Y[i] >> Z[i]; vector dp(1<<N, 0LL); dp[0] = 1; for(int i=1;i<(1<<N);i++){ bool ok = true; REP(j,M){ if(__builtin_popcount(i) != X[j]) continue; int cnt2 = 0; REP(k,Y[j]) if(i >> k & 1) cnt2++; if(cnt2 > Z[j]) ok = false; } if(!ok) continue; REP(j,N) if(i >> j & 1) dp[i] += dp[i^(1<<j)]; } cout << dp[(1<<N)-1] << endl;; }