int fa[N]; intfindset(int x){ return fa[x] == -1? x : fa[x] = findset(fa[x]); }
intsolve(){ int n, m; cin >> n >> m; fill(fa, fa + n + 1, -1); int cnt = 0; FOR (_, 0, m) { int u, v; scanf("%d%d", &u, &v); int fu = findset(u), fv = findset(v); if (fu != fv) { ++cnt; fa[fu] = fv; } } return2 * (n - 1) - cnt; }
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: %d\n", Ca, solve()); } }
Code-Eat Switcher
判断点是否在凸包内。先不考虑把一个 time slot 分割的情况,肯定是按照某一方(比如 coding)的性价比排序,然后一侧全是 coding,另一侧全是 eating。每一个分界线的位置对应一个点,考虑所有点,把相邻的连起来,就是所有最优解构成的凸包。剩下的问题就是如何判断一个点是否在凸包内了,找出这个点 x 轴上附近的两个点(二分搜索),看是否在那两个点构成的直线的下方(叉积判正负)。
const LL p_max = 1E6 + 100; LL pr[p_max], p_sz; voidget_prime(){ staticbool vis[p_max]; FOR (i, 2, p_max) { if (!vis[i]) pr[p_sz++] = i; FOR (j, 0, p_sz) { if (pr[j] * i >= p_max) break; vis[pr[j] * i] = 1; if (i % pr[j] == 0) break; } } }
constint N = 1E5 + 100; bool f[N]; set<LL> S;
voidcount(LL L, LL R, LL multiplier = 1){ if (L > R) return; fill(f, f + R - L + 1, true); FOR (i, 0, p_sz) { LL p = pr[i]; if (p * p > R) break; FOR (j, max((L + p - 1) / p, 2LL), R / p + 1) { f[j * p - L] = false; } } FOR (i, L, R + 1) if (f[i - L]) S.insert(i * multiplier); }
voidsolve(){ S.clear(); LL L, R; cin >> L >> R; count(L, R); FOR (i, L, R + 1) if ((i & 3) == 2) S.insert(i); count((L + 3) / 4, R / 4, 4); if (L <= 4 && 4 <= R) S.insert(4); if (L <= 8 && 8 <= R) S.insert(8); dbg(S); cout << S.size() << endl; }
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif get_prime(); int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
int n, S; cin >> n >> S; FOR (i, 0, n) { x.clear(); int k; scanf("%d", &k); FOR (_, 0, k) { int t; scanf("%d", &t); x.push_back(t); } sort(x.begin(), x.end()); FOR (j, 1, 1 << x.size()) { LL v = 0; FOR (k, 0, x.size()) if ((j >> k) & 1) v = v * 1001 + x[k]; ++mp[v]; if (j == (1 << x.size()) - 1) a.push_back(v); } } LL ans = 0; for (LL& v: a) ans += n - mp[v]; cout << ans << endl; }
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
constint N = 1E5 + 100; vector<int> a[N]; int c[N], d[N];
intmain(){ FOR (i, 1, N) for (int j = i; j < N; j += i) a[j].push_back(i); int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); int n, m, Q; cin >> n >> m >> Q; FOR (i, 0, m) scanf("%d", d + i); FOR (i, 0, m) for (int t: a[d[i]]) ++c[t]; LL ans = 0; FOR (_, 0, Q) { int x; scanf("%d", &x); ans += n / x - c[x]; } printf("%lld\n", ans); FOR (i, 0, m) for (int t: a[d[i]]) --c[t]; } }
constint N = 20 + 10; using VLL = vector<pair<LL, LL>>; VLL L, R; pair<LL, LL> a[N];
voidgo(const VLL& a, pair<LL, LL> s, VLL& ret, int k){ if (k == a.size()) { ret.push_back(s); return; } go(a, {s.first + a[k].first, s.second + a[k].second}, ret, k + 1); go(a, {s.first, s.second + a[k].second}, ret, k + 1); go(a, {s.first + a[k].first, s.second}, ret, k + 1); }
#include<ext/pb_ds/assoc_container.hpp> usingnamespace __gnu_pbds; using Tree = tree<pair<LL, int>, null_type, less<>, rb_tree_tag, tree_order_statistics_node_update>; Tree t;
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); L.clear(); R.clear(); t.clear(); int n; LL H; cin >> n >> H; FOR (i, 0, n) scanf("%lld", &a[i].first); FOR (i, 0, n) scanf("%lld", &a[i].second); go(VLL(a, a + n / 2), {0, 0}, L, 0); go(VLL(a + n / 2, a + n), {0, 0}, R, 0); sort(L.begin(), L.end()); sort(R.begin(), R.end(), greater<>()); LL k = 0, ans = 0; int clk = 0; for (auto& x: L) { while (k < R.size() && R[k].first + x.first >= H) t.insert({R[k++].second, clk++}); ans += k - t.order_of_key({H - x.second, -1}); } cout << ans << endl; } }
Round H
H-Index
方法1:无脑模拟,相比起方法2代码复杂度高了一些,但是思维复杂度很低。需要有一个支持边插入边查询求第 K 大,或者求小于某个数的数量的数据结构。代码中使用了树状数组。
constint M = 1e5 + 100; namespace bit { LL c[M]; inlineintlowbit(int x){ return x & -x; } voidadd(int x, LL v){ for (int i = x; i < M; i += lowbit(i)) c[i] += v; } LL sum(int x){ LL ret = 0; for (int i = x; i > 0; i -= lowbit(i)) ret += c[i]; return ret; } }
voidsolve(){ int n; cin >> n; int h = 0; vector<int> history; FOR (i, 0, n) { int v; scanf("%d", &v); history.push_back(v); bit::add(v, 1); while (i + 1 - bit::sum(h) >= h + 1) h += 1; printf("%d ", h); } for (int& v: history) bit::add(v, -1); puts(""); }
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
intfix(int n, int x, int y){ int cnt = 0, sum = 0; while (x < n && y < n) { cnt += 1; sum += G[x][y]; ++x; ++y; } if (cnt == sum) return0; if (sum == 0) return1; return INF; }
voidflip(bool& f){ f = !f; }
intcheck(int n, int op1, int op2){ memcpy(G, GG, sizeof G); int ans = op1 + op2; FOR (i, 0, n) { if (op1) flip(G[i][i]); if (!G[i][i]) { ++ans; FOR (j, 0, i + i + 1) { flip(G[j][i + i - j]); } } } FOR (i, 0, n - 1) { if (op2) flip(G[i][i + 1]); if (!G[i][i + 1]) { ++ans; FOR (j, 0, i + i + 2) { flip(G[j][i + i + 1 - j]); } } } FOR (i, 0, n) ans += fix(n, i, 0) + fix(n, 0, i); return ans; }
voidsolve(){ int n; cin >> n; FOR (i, 0, n) { scanf("%s", s); FOR (j, 0, n) GG[i][j] = s[j] == '#'; } int ans = INF; FOR (op1, 0, 2) FOR (op2, 0, 2) ans = min(ans, check(n, op1, op2)); cout << ans << endl; }
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
constint N = 100 * 2 * 2 * 2 + 10; vector<int> G[N], rG[N], vs; int used[N], cmp[N];
voidadd_edge(int from, int to){ G[from].push_back(to); rG[to].push_back(from); }
voiddfs(int v){ used[v] = true; for (int u: G[v]) { if (!used[u]) dfs(u); } vs.push_back(v); }
voidrdfs(int v, int k){ used[v] = true; cmp[v] = k; for (int u: rG[v]) if (!used[u]) rdfs(u, k); }
intscc(int n){ memset(used, 0, sizeof(used)); vs.clear(); for (int v = 0; v < n; ++v) if (!used[v]) dfs(v); memset(used, 0, sizeof(used)); int k = 0; for (int i = (int) vs.size() - 1; i >= 0; --i) if (!used[vs[i]]) rdfs(vs[i], k++); return k; }
char s[N]; int ans[N * 8], cnt[N * 8]; voidsolve(){ int n; cin >> n; FOR (i, 0, n * 8) { G[i].clear(); rG[i].clear(); } // i, j // /: (i + j) * 2 ^ ? // \: (i - j + 3 * n) * 2 ^ ? FOR (i, 0, n) { scanf("%s", s); FOR (j, 0, n) { int u = (i + j) * 2, v = (i - j + 3 * n) * 2; if (s[j] == '#') { add_edge(u, v); add_edge(u ^ 1, v ^ 1); add_edge(v, u); add_edge(v ^ 1, u ^ 1); } else { add_edge(u, v ^ 1); add_edge(u ^ 1, v); add_edge(v, u ^ 1); add_edge(v ^ 1, u); } } } int k = scc(n * 8); dbg(k); memset(ans, 0, sizeof ans); memset(cnt, 0, sizeof cnt); FOR (i, 0, n * 8) if (i % 2 == 0) { if (G[i].empty()) continue; assert(cmp[i] != cmp[i ^ 1]); int kk = min(cmp[i], cmp[i ^ 1]); dbg(i, cmp[i], cmp[i + 1]); cnt[kk] += 1; ans[kk] += cmp[i] > cmp[i ^ 1]; } int res = 0; FOR (i, 0, k) { res += min(ans[i], cnt[i] - ans[i]); } cout << res << endl; }
intmain(){ #ifdef zerol freopen("in", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
voidsolve(){ int n; cin >> n; string s; cin >> s; int last = 33, ans = 0; FOR (i, 0, n) { int c = s[i] - 'A'; if (c <= last) ans = 1; else ++ans; last = c; printf("%d%c", ans, i == _i - 1 ? '\n' : ' '); } }
intmain(){ #ifdef zerol freopen("in.txt", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
const LL MOD = 1e9 + 7; constint N = 1e5 + 100; char s[N], ss[N];
voidsolve(){ int n, k; cin >> n >> k >> s; int m = (n + 1) / 2; FOR (i, 0, m) { ss[i] = ss[n - 1 - i] = s[i]; } bool f = strcmp(ss, s) >= 0; LL ans = 0; FOR (i, 0, m) { dbg(i, s[i] - 'a'); ans = ans * k + (s[i] - 'a'); ans %= MOD; } cout << (ans + 1 - f) % MOD << endl; }
intmain(){ #ifdef zerol freopen("in.txt", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
voidcheck(LL x, LL k){ LL u = x / k + 1 - k; if (u >= 1 && u % 2 == 0) { ans += 1; } }
voidsolve(){ LL x; cin >> x; // x / n * 2 = k + k + n - 1 ans = 0; x *= 2; FOR (i, 1, LL(sqrt(x + 0.5) + 1)) { if (i * i == x) { check(x, i); } elseif (x % i == 0) { check(x, i); check(x, x / i); } } cout << ans << endl; }
intmain(){ #ifdef zerol freopen("in.txt", "r", stdin); #endif int T; cin >> T; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } }
Rock Paper Scissors
题意:石头剪刀布的交互题,题意有些复杂。每一天的得分规则不同,赢了得 W 分,平了得 E 分,其中 E 有四种可能的取值,为 \(W, W / 2, W / 10, 0\)。对手的策略是已知的,它出石头、剪刀、布的概率之比为那天之前你出的剪刀、布、石头的次数的比例,特别地,第一天视为等概率。目标是 200 天后(每天都是独立的),期望收益超过某个定值。
这题翻车了,我认定这是我擅长的构造题,四种情况分类讨论一下,然后凑出一个足够优的策略就好了。然后题意没读清楚把自己坑了,然后又凑了一通也没凑出来,最后只过了 Test Set 1。过 Test Set 1 的方案很简单,每天按照石头、剪刀、布的顺序出就行了。赛后看了题解,惊了,这竟然是 DP 题???
官方题解 for Test Set 2:随机生成策略,用随机优化算法来找到一个足够好的。
官方题解 for Test Set 3:\(f[a][b][c]\) 为第 \(a+b+c\) 天石头剪刀布分别出了 \(a, b, c\) 次的最佳期望收益,最后把最优路径输出来就好了,状态转移也很简单。
constint N = 60, M = N + 5; int c[M]; int W, E; double all;
voidoutput(){ int cnt[3] = {0, 0, 0}; double rp[3] = {1.0 / 3, 1.0 / 3, 1.0 / 3}; double profit = 0; FOR (i, 0, N) { if (c[i] == 0) putchar('R'); if (c[i] == 1) putchar('S'); if (c[i] == 2) putchar('P'); profit += W * rp[(c[i] + 1) % 3] + E * rp[c[i]]; cnt[c[i]] += 1; FOR (j, 0, 3) rp[(j + 2) % 3] = 1.0 * cnt[j] / (i + 1); } all += profit; puts(""); }
pair<double, int> f[M][M][M]; int from[M][M][M]; voidsolve(){ cin >> W >> E; f[1][0][0] = {0, 0}; f[0][1][0] = {0, 1}; f[0][0][1] = {0, 2}; int ii, jj, kk; double ans = -1; FOR (i, 0, N + 1) FOR (j, 0, N + 1) FOR (k, 0, N + 1) { int s = i + j + k; double ss = s - 1; if (s <= 1 || s > N) continue; f[i][j][k] = max({ make_pair(i ? f[i - 1][j][k].first + k * W / ss + j * E / ss : -1, 0), make_pair(j ? f[i][j - 1][k].first + i * W / ss + k * E / ss : -1, 1), make_pair(k ? f[i][j][k - 1].first + j * W / ss + i * E / ss : -1, 2), }); if (s == N && f[i][j][k].first > ans) { ii = i; jj = j; kk = k; ans = f[i][j][k].first; } } dbg(ans); FORD (i, N - 1, -1) { c[i] = f[ii][jj][kk].second; if (c[i] == 0) --ii; elseif (c[i] == 1) --jj; elseif (c[i] == 2) --kk; } output(); }
intmain(){ #ifdef zerol freopen("in.txt", "r", stdin); #endif int T, X; cin >> T >> X; FOR (Ca, 1, T + 1) { printf("Case #%d: ", Ca); solve(); } dbg(all / 200); }
intck(int x, int y, int z){ return y * 2 - x - z == 0; }
map<int, int> mp; voidadd(int x, int y){ int v = x + y; if (v % 2 == 0) mp[v] += 1; }
voidsolve(){ mp.clear(); FOR (i, 0, N) FOR (j, 0, N) if (i != 1 || j != 1) { scanf("%d", &a[i][j]); } int s = 0; s += ck(a[0][0], a[0][1], a[0][2]); s += ck(a[2][0], a[2][1], a[2][2]); s += ck(a[0][0], a[1][0], a[2][0]); s += ck(a[0][2], a[1][2], a[2][2]); add(a[0][0], a[2][2]); add(a[0][2], a[2][0]); add(a[0][1], a[2][1]); add(a[1][0], a[1][2]); int m = 0; for (auto it: mp) { m = max(m, it.second); } printf("%d\n", s + m); }
voiddel(LL x){ auto u = *--s.upper_bound({x, -1}); assert(u.l <= x && x <= u.r); s.erase(u); ins(u.l, x - 1); ins(x + 1, u.r); }
LL find_l(LL x){ auto it = s.upper_bound({x, -1}); if (it == s.begin()) return -INF; auto u = --it; if (u->l <= x && x <= u->r) return x; return u->r; }
LL find_r(LL x){ auto u = s.lower_bound({x, -1}); if (u == s.end()) return -INF; return u->l; }
voidsolve(){ s.clear(); int n, m; cin >> n >> m; FOR (i, 0, n) { LL l, r; scanf("%lld%lld", &l, &r); s.insert({l, r}); } FOR (i, 0, m) { LL v; scanf("%lld", &v); LL l = find_l(v), r = find_r(v); LL ans = abs(l - v) <= abs(r - v) ? l : r; del(ans); printf("%lld ", ans); } puts(""); }
voidsolve(){ string s; cin >> s; int sum = 0; for (auto c: s) { sum += c - '0'; } sum %= 9; sum = (9 - sum) % 9; int i = 0; for (; i < s.size(); ++i) { if (s[i] - '0' > sum && (i != 0 || sum != 0)) { break; } putchar(s[i]); } putchar('0' + sum); for (; i < s.size(); ++i) { putchar(s[i]); } puts(""); }
for (auto c: s) { nxt.clear(); FOR (cc, '0', '2') { if (c != cc && c != '?') continue;
for (auto& x: S) { string xx = x + cc; if (check(xx)) { if (xx.length() > 6) xx = xx.substr(1, 6); nxt.insert(xx); } } } S.swap(nxt); } if (S.empty()) puts("IMPOSSIBLE"); elseputs("POSSIBLE"); }
LL dfs(LL pos, LL p, LL s, int target, bool limit){ if (s > target) return0; if (pos == -1) { LL ret = (s == target && p == 0); return ret; } if (!limit && f[pos][p][s][target] != -1) return f[pos][p][s][target]; LL ret = 0; LL ed = limit ? a[pos] : 9; FOR (i, 0, ed + 1) { tmp[pos] = i; LL pp = p * i % target; if (s == 0 && i == 0) pp = p; ret += dfs(pos - 1, pp, s + i, target, limit && i == a[pos]); }
if (!limit) f[pos][p][s][target] = ret; return ret; }
LL go(LL x, int target){ LL sz = 0; LL xx = x; while (x) { a[sz++] = x % 10; x /= 10; } LL ret = dfs(sz - 1, 1, 0, target, true); return ret; }
voidsolve(){ LL l, r; cin >> l >> r; LL ans = 0; FOR (i, 1, 9 * 12 + 1) { ans += go(r, i) - go(l - 1, i); } cout << ans << endl; }
voidget_z(int a[], char s[], int n){ int l = 0, r = 0; a[0] = n; FOR (i, 1, n) { a[i] = i > r ? 0 : min(r - i + 1, a[i - l]); while (i + a[i] < n && s[a[i]] == s[i + a[i]]) ++a[i]; if (i + a[i] - 1 > r) { l = i; r = i + a[i] - 1; } } } constint N = 1e5 + 100; char s[N]; int a[N]; voidsolve(){ int n; cin >> n >> s; get_z(a, s, n); FOR (i, 1, n) { if (n % i != 0) continue; if (a[i] == n - i) { FOR (j, 0, i) putchar(s[j]); puts(""); return; } } puts(s); }