https://beta.atcoder.jp/contests/arc101
本番解けないと意味ないってそれ一番。
コンテスト中は1完です…
C
K個の連続した区間になるので適切に計算すればO(N)。
D
本番誤読してかなしぃ。中央値はやっぱりにぶたんなんだよなぁ。
https://agc006.contest.atcoder.jp/tasks/agc006_d
これっぽいですね。
ll N; ll A[MAX_N]; int S[MAX_N]; pi P[MAX_N]; bool ok(ll m) { rep(i, 0, N) { if(A[i] <= m) S[i + 1] = 1; else S[i + 1] = -1; } // debug(m, vi(S + 1, S + N + 1)); rep(i, 0, N) { S[i + 1] += S[i]; } rep(i, 0, N + 1) { P[i] = pi(S[i], -i); } sort(P, P + N + 1); ll res = 0; BIT bit(N + 1); rep(i, 0, N + 1) { int at = P[i].sec * -1; bit.update(at, at + 1, 1); res += bit.get(0, at); } return res > N * (N + 1) / 4; } void solve() { cin >> N; rep(i, 0, N) cin >> A[i]; ll lv = 0, rv = inf; while(rv - lv > 1) { ll m = (lv + rv) / 2; if(ok(m)) rv = m; else lv = m; } cout << rv << "\n"; }
E
dp[v][a]:=根がvの木で余ってる辺がk本の時とすると、
dp[v][a+b-2k]:=dp[c1][a]*dp[c2][b]*C(a,k)*C(b,k)とかになって、なんとかまとめればできそうな形になりますが全然できません。本番もこれでめちゃくちゃハマりました。
なのでこの考えから離れましょう。包除を思いつけるとあとはそんな難しくないです。
木dpの書き方も忘れてたのでよい練習になりました。
int N; vector<int> G[MAX_N]; ll dp[5010][5010][2]; ll ep[5010][5010][2]; ll pow2inv[5010]; int loop(int v, int p) { int sz = 1; dp[v][1][0] = 1; rep(q, 0, sz(G[v])) { int n = G[v][q]; if(p == n) continue; int ts = loop(n, v); rep(i, 0, sz + ts + 1) { rep(j, 0, 2) { ep[v][i][j] = 0; } } rep(i, 0, sz + 1) { rep(j, 0, ts + 1) { rep(k, 0, 2) { rep(l, 0, 2) { ADD(ep[v][i + j][(k + l) % 2], dp[v][i][k] * dp[n][j][l] % mod); } } } } rep(i, 0, sz + ts + 1) { rep(j, 0, 2) { dp[v][i][j] = ep[v][i][j]; } } sz += ts; } for(int i = 0; i <= sz; i += 2) { rep(j, 0, 2) { ADD(dp[v][0][(j + 1) % 2], dp[v][i][j] * fac[i] % mod * pow2inv[i / 2] % mod * fiv[i / 2] % mod); } } return sz; } void solve() { cin >> N; C_init(N); rep(i, 0, N - 1) { int a, b; cin >> a >> b; a--; b--; G[a].pb(b); G[b].pb(a); } pow2inv[0] = 1; rep(i, 0, N) { pow2inv[i + 1] = pow2inv[i] * inv[2] % mod; } loop(0, -1); cout << (dp[0][0][1] - dp[0][0][0] + mod) % mod << "\n"; }
F
解説とだいぶ違った。
ロボットの出口との距離を(a,b)とします。座標の点をグラフにして、0から正の方向負の方向に辺を張ります。
それから(a->b)または(b->a)の辺を張ってグラフ全体がトポロジカルソートができることが条件になります。
トポロジカルソートができる<=>ループが存在しない<=>(a,b)(c,d)の組であってa<=c,b<=dを満たし、a->b,d->cに辺を張るものが存在しない
と言い換えられます。ここまでくればあとはBITで数え上げられます。
でも解説の2次元座標の言い換えができたほうが絶対良かったよなぁ。
int N, M; ll X[MAX_N], Y[MAX_N]; ll L[MAX_N], R[MAX_N]; vl vec; vl Q[MAX_N]; int fd(ll v) { return lower_bound(all(vec), v) - vec.begin(); } void solve() { cin >> N >> M; rep(i, 0, N) cin >> X[i + 1]; rep(i, 0, M) cin >> Y[i + 1]; X[0] = -linf; Y[M + 1] = linf; int at = 1; rep(i, 0, N) { while(X[i + 1] > Y[at]) at++; if(at != M + 1) R[i] = Y[at] - X[i + 1]; else R[i] = linf; vec.pb(R[i]); } at = M; rer(i, N, 0) { while(X[i + 1] < Y[at]) at--; if(at != 0) L[i] = X[i + 1] - Y[at]; else L[i] = linf; vec.pb(L[i]); } vec.pb(linf); sort(all(vec)); // debug(vl(L, L + N)); // debug(vl(R, R + N)); vec.erase(unique(all(vec)), vec.end()); rep(i, 0, N) { int lat = fd(L[i]), rat = fd(R[i]); Q[lat].pb(rat); } rep(i, 0, sz(vec)) { sort(all(Q[i])); Q[i].erase(unique(all(Q[i])), Q[i].end()); } BIT bit(sz(vec)); bit.update(sz(vec) - 1, sz(vec), 1); rer(i, sz(vec) - 1, 0) { rep(j, 0, sz(Q[i])) { int b = Q[i][j]; ll v = bit.get(b + 1, sz(vec)); // debug(vec[i], vec[b], v); bit.update(b, b + 1, v); } } cout << bit.get(0, sz(vec)) << "\n"; }