Bondo416さんのトヨタ自動車プログラミングコンテスト2023#1(AtCoder Beginner Contest 298)での成績:385位#AtCoder #トヨタ自動車プログラミングコンテスト2023#1(ABC298) https://t.co/ua5tDpS8Jt
— ボンド@競プロ (@bond_cmprog) April 15, 2023
A - Job Interview
o
があるかどうかとx
があるかどうかをそれぞれ確認する
void solve() { int N; string S; cin >> N >> S; bool ok1 = false; bool ok2 = true; REP(i, N) { if (S[i] == 'o') ok1 |= true; if (S[i] == 'x') ok2 = false; } cout << (ok1 and ok2 ? "Yes" : "No") << endl; }
B - Coloring Matrix
4回回転させれば元に戻るので全探索する
void solve() { int N; cin >> N; vector<vector<int>> A(N, vector<int>(N)); auto B = A; REP(i, N) REP(j, N) cin >> A[i][j]; REP(i, N) REP(j, N) cin >> B[i][j]; REP(_, 4) { bool ok = true; REP(i, N) REP(j, N) { if (A[i][j] == 1 and B[i][j] == 0) ok = false; } if (ok) { cout << "Yes" << endl; return; } auto a = A; REP(i, N) REP(j, N) { A[i][j] = a[N - j - 1][i]; } } cout << "No" << endl; }
C - Cards Query Problem
箱は重複を許すmultiset、数は重複なしのsetで管理する
void solve() { int N, Q; cin >> N >> Q; vector<multiset<int>> hako(202020); vector<set<int>> number(202020); while (Q--) { int q; cin >> q; if (q == 1) { int i, j; cin >> i >> j; hako[j].emplace(i); number[i].emplace(j); } else if (q == 2) { int i; cin >> i; for (auto x : hako[i]) { cout << x << " "; } cout << endl; } else { int i; cin >> i; for (auto x : number[i]) { cout << x << " "; } cout << endl; } } }
D - Writing a Numeral
先頭の要素取得と削除が可能なdequeで管理しながら追加、削除で差分計算をしていく
よく考えるとqueueでも良かった
void solve() { int Q; cin >> Q; mint sum = 1; deque<int> dq; dq.push_front(1); while (Q--) { int q; cin >> q; if (q == 1) { int x; cin >> x; dq.push_back(x); sum = sum * 10 + x; } else if (q == 2) { int d = dq.size(); int x = dq.front(); dq.pop_front(); sum = sum - modpow(mint(10), d - 1) * x; } else cout << sum << endl; } }
E - Unfair Sugoroku
青木くんと高橋くんそれぞれ独立に考えていいので、以下のDPを求める
$ dp[i][j] := i $ 回目に地点 $ x $ にいる確率
高橋くんが $ i $ 回目に勝つ確率は、高橋くんが$ i $ 回目に地点 $ N $ にいる確率と青木くんが $ i - 1 $ 回目に地点 $ N $ 以外にいる確率との積になるのでその総和を求めればいい
void solve() { int N, A, B, P, Q; cin >> N >> A >> B >> P >> Q; vector<vector<mint>> aoki(N + 1, vector<mint>(N + 1, 0)); aoki[0][B] = 1; REP(k, N) { REP(i, N) REP(j, 1, Q + 1) { int to = (i + j > N ? N : i + j); aoki[k + 1][to] += aoki[k][i] / Q; } } vector<vector<mint>> takahashi(N + 1, vector<mint>(N + 1, 0)); takahashi[0][A] = 1; REP(k, N) { REP(i, N) REP(j, 1, P + 1) { int to = (i + j > N ? N : i + j); takahashi[k + 1][to] += takahashi[k][i] / P; } } mint ans = 0; REP(i, 1, N + 1) { if (takahashi[i][N] == 0) continue; mint p = 0; REP(j, N) p += aoki[i - 1][j]; ans += p * takahashi[i][N]; } cout << ans << endl; }
F - Rook Score
座圧をして平面走査を行う
$ r $ 行目の総和をセグメント木で管理し、その最大値を求める
$ w $ 列目の総和をそれぞれ求めながら重複する$ r $行目の差分計算を行い最大値を更新していく
void solve() { int N; cin >> N; Compress<ll> cmp_h; vector<ll> h(N), w(N), x(N); REP(i, N) { cin >> h[i] >> w[i] >> x[i]; cmp_h.add(h[i]); } cmp_h.build(); int sz = cmp_h.size() + 1; map<ll, vector<LP>> mpw; vector<ll> h_val(sz + 1); REP(i, N) { mpw[w[i]].emplace_back(cmp_h.get(h[i]), x[i]); h_val[cmp_h.get(h[i])] += x[i]; } ll ans = 0; segtree<ll, op, e> seg(h_val); for (auto [k, v] : mpw) { ll sum = 0; for (auto [h_idx, x] : v) { seg.set(h_idx, seg.get(h_idx) - x); sum += x; } chmax(ans, sum + seg.all_prod()); for (auto [h_idx, x] : v) { seg.set(h_idx, seg.get(h_idx) + x); } } cout << ans << endl; }