structnode { ll a, b, sum; } a[maxN]; boolcmp(node a, node b){ return a.sum > b.sum; }
主函数:
1 2 3 4 5 6 7
// 输入略 for (int i = 0; i < n; ++i) a[i].sum = a[i].a + a[i].b; std::sort(a, a + n, cmp); ll ans = 0; for (int i = 0; i < n / 2; ++i) ans += a[2*i].a - a[2*i+1].b; if (n & 1) ans += a[n-1].a - 1; printf("%lld\n", ans);
int n = read(); vector v(n+1, 0); for (int i = 1; i <= n; ++i) v[i] = read(); sort(v.begin(), v.end()); bool op = 0; for (int i = 1; i <= n; ++i) { if (v[i] - v[i-1] > 0) op ^= 1; if (v[i] - v[i-1] > 1) break; } printf("%s\n", op ? "Alice" : "Bob");
倒着写:
1 2 3 4 5 6 7 8
bool op = 0; for (int i = n; i >= 1; i--) { if (v[i] - v[i-1] > 0) { if (op == 0) op = 1; elseif (v[i] - v[i-1] == 1) op = 0; } } printf("%s\n", op ? "Alice" : "Bob");
题意n 个数,小 A 每次选择一个数倒过来并删掉前导零,小 B 每次将一个数拼到另一个数上。如果最后剩下的数≥10m,则小 B 赢,否则小 A 赢。
思路 小 B 最终的目标其实是所有数的数位和>m,所以他要确保删去的前导零最少,小 A 则要删去的最多。将一个数拼到另一个数的高位,就相当于保护了这些前导零不被删掉。设ci 为ai 后导零的个数,s 为所有数的位数之和,那么问题变为: 小 A 每次可以选一个数拿走,小 B 也可以。如果最后小 A 拿走的数之和≤s−m,那么小 B 赢,否则小 A 赢。 那么两人的最优策略都是拿走当前最大的一个,直接模拟即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
int n = read(), m = read(); ll sum = 0; for (int i = 1; i <= n; ++i) { int x = read(); a[i] = 0; while (x % 10 == 0) x /= 10, ++a[i], ++sum; while (x) x /= 10, ++sum; } std::sort(a + 1, a + n + 1, greater<int>()); for (int i = 1; i <= n; i += 2) { sum -= a[i]; } printf("%s\n", sum <= m ? "Anna" : "Sasha");
longdoubleSqrt(longdouble n) { longdouble s = sqrt(n); for (int i = 1; i <= n; ++i) s = n / s; return s; }
intmain(){ int n, m; cin >> n >> m; if (n < m)swap(n, m); int ans = (n - m) * (Sqrt(5.0) + 1.0) / 2.0; if (ans == m)cout << "0" << endl; else cout << "1" << endl; return0; }
intmain(){ int T; cin >> T; while (T--) { int n; cin >> n; int ans = 0; while (n--) { int m; cin >> m; memset(a, 0, sizeof a); int cnt = 20 - m + 1, tot = 0, sg = 0;//阶梯总数,石子数,本行sg while (m--) { int tmp; cin >> tmp; a[tmp] = 1; } for (int i = 1; i <= 20; i++) { if (!a[i]) { if ((--cnt) & 1) {//奇数台阶计入sg sg ^= tot; } tot = 0; } else tot++; } ans ^= sg; } if (ans)cout << "YES" << endl; else cout << "NO" << endl; } return0; }
intdfs1(int m, std::vector<int> v){ int sg = 0; int a[1000] = { 0 }, nim[1000] = { 0 }; std::sort(v.begin(), v.end()); for (int j = 1; j <= m; ++j) { a[j] = 20 - v[j]; } int de = 0; memset(nim, 0, sizeof nim); for (int j = m; j >= 1; --j) { nim[a[j] - de] += 1; de += 1; } for (int j = 1; j <= 20; j += 2) { sg ^= nim[j]; }
return sg; }
intdfs2(int m, std::vector<int> v){ int ans = 0; int aa[1000] = { 0 }; int cnt = 20 - m + 1, tot = 0, sg = 0;//阶梯总数,石子数,本行sg for (int j = 1; j <= m; ++j) { aa[v[j]] = 1; } for (int i = 1; i <= 20; i++) { if (!aa[i]) { if ((--cnt) & 1) {//奇数台阶计入sg sg ^= tot; } tot = 0; } else tot++; } ans ^= sg; return ans; }
intmain(){ for (int x = 0; x < (1ll << 20); ++x) { std::vector<int> v; v.push_back(-1); for (int i = 0; i < 20; ++i) { if (x & (1ll << i)) { v.push_back(i + 1); } } if (v.size() == 0) continue; int ans1 = dfs1(v.size() - 1, v); int ans2 = dfs2(v.size() - 1, v); if (ans1 != ans2) { printf("%d\n%d %d\n", v.size(), ans1, ans2); for (auto& i : v) { printf("%d ", i); } } }
for (int t = read(); t--;) { int n = read(); int ans = 0; for (int i = 1; i <= n; ++i) { int m = read(); std::vector<int> v; v.push_back(-1); for (int j = 1; j <= m; ++j) { v.push_back(read()); } ans ^= dfs1(m, v); } printf("%s\n", ans ? "YES" : "NO"); }
#include<iostream> #include<cmath> #include<algorithm> #include<cstring> usingnamespace std; constint maxn = 1000; int sg[maxn], flag[maxn]; voidgetsg(int n, int p, int q){ memset(sg, 0, sizeof(sg)); for (int i = p + 1; i <= n; i++){ memset(flag, 0, sizeof(flag)); for (int j = p; j <= q; j++){ flag[sg[i - j]] = 1; } for (int j = 0; ; j++){ if (flag[j] == 0) { sg[i] = j; break; } } } for (int i = 0; i <= n; i++){ cout << "sg_" << i << ":" << sg[i] << endl; }
} intmain(){ int n, p, q; while (cin >> n >> p >> q) { //getsg(n, p, q); int mod = n % (p + q); if (mod >= 1 && mod <= p)cout << "LOST" << endl; else cout << "WIN" << endl; } return0; }
intmain(){ int n, m, a, b, ans; while (cin >> n >> m) { int ans = 0; for (int i = 1; i <= n; i++) { cin >> a >> b; int d = abs(a - b) - 1; ans ^= d; } if (ans) cout << "I WIN!" << endl; else cout << "BAD LUCK!" << endl; } return0; }
#include<algorithm> #include<cmath> #include<cstring> #include<string> #include<iostream> usingnamespace std; using ll = longlong; constint N = 1e6 + 8; int trie[N][26]; int pcnt = 0;
voidinsert(string& s){ int p = 0; for(auto c: s){ if (trie[p][c - 'a'] == -1) trie[p][c - 'a'] = ++pcnt; p = trie[p][c - 'a']; } }
intdfs(int n){ int sum = 0; int ans = 0; for (int i = 0; i < 26; i++){ if (trie[n][i] == -1) continue; else{ sum++; int res = dfs(trie[n][i]); ans |= res ^ 3; } } if (sum == 0) return2;//叶子节点 else return ans; }
//ans = 1 win //ans = 2 lost //ans = 3 win or lost //ans = 0 do not know
intmain(){ int n,k; string s; cin >> n >> k; memset(trie, -1, sizeof trie); for (int i = 1; i <= n; i++){ cin >> s; insert(s); } int ans = dfs(0); if(ans == 1){ if (k & 1) cout << "First" << endl; else cout << "Second" << endl; } elseif(ans == 2 || ans == 0){ cout << "Second" << endl; } else cout << "First" << endl; return0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> usingnamespace std; using ll = longlong;
intmain(){ int T; cin >> T; for (int Ti = 1; Ti <= T; Ti++) { int n; cin >> n; ll a = 0, b = 0; while (n--) { int x, y; cin >> x >> y; while (x > 1 && y > 1) { x >>= 1; y >>= 1; } if (y == 1) a += x - 1; if (x == 1) b += y - 1; } printf("Case %d: %s\n", Ti, a > b ? "Alice" : "Bob"); } return0; }
J. 树和博弈 CF-1404B
[[…/图论 - 树/树习题集#树和博弈 CF-1404B]]
题意 树上博弈。两人从起始点a,b 轮流跳,每次跳跃上界为da,db。若 A 和 B 重合,则 A 胜,否则在足够长的时间内都不能重合,则 B 胜。判断胜负。([[…/数学/博弈论#J. 树和博弈 CF-1404B]])
constexprint N = 1e5 + 8; vector<int> E[N]; int d, dp1[N], dp2[N]; int pa[30][N], dep[N], Log2[N];
voiddfs(int u, int p = 0){ dep[u] = dep[p] + 1; pa[0][u] = p; for (int i = 1; i <= Log2[dep[u]]; ++i) pa[i][u] = pa[i - 1][pa[i - 1][u]]; dp1[u] = dp2[u] = 0;
for (auto &v : E[u]) { if (v == p) continue; dfs(v, u); int t = dp1[v] + 1; if (t > dp1[u]) dp2[u] = dp1[u], dp1[u] = t; elseif (t > dp2[u]) dp2[u] = t; } d = max(d, dp1[u] + dp2[u]); }
intgetlca(int u, int v){ if (dep[u] > dep[v]) swap(u, v); while (dep[u] != dep[v]) v = pa[Log2[dep[v] - dep[u]]][v]; if (u == v) return u; for (int bit = Log2[dep[u]]; bit >= 0; --bit) { if (pa[bit][u] != pa[bit][v]) u = pa[bit][u], v = pa[bit] } return pa[0][u]; }
intgetd(int u, int v){ return dep[u] + dep[v] - 2 * dep[getlca(u, v)]; }
voideachT(){ int n = read(), a = read(), b = read(), da = read(), db = read(); for (int i = 2; i <= n; ++i) { int u = read(), v = read(); E[u].push_back(v), E[v].push_back(u); }
// DP求树直径 dfs(1);
// 计算答案 bool ans; if (getd(a, b) <= da) ans = 1; // 一步就死 elseif (da >= db) ans = 1; // A 的跳远更牛 elseif (d <= 2 * da) ans = 1; // A 全覆盖 elseif (db >= 2 * da + 1) ans = 0; // B 来回跳跃 else ans = 1; printf("%s\n", ans ? "Alice" : "Bob");
// 初始化 d = 0; for (int u = 1; u <= n; ++u) { for (int i = 0; i < 33; ++i) pa[i][u] = 0; dp1[u] = dp2[u] = dep[u] = 0; E[u].clear(); } }
intmain(){ for (int i = 2; i < N; ++i) Log2[i] = Log2[i / 2] + 1; for (int t = read(); t--;) eachT(); return0; }
constexprint N = 1e5 + 8; vector<int> E[N]; int dep[N];
voiddfs(int u, int p = 0){ dep[u] = dep[p] + 1; for (auto &v : E[u]) if (v != p) dfs(v, u); }
voideachT(){ int n = read(), a = read(), b = read(), da = read(), db = read(); for (int i = 2; i <= n; ++i) { int u = read(), v = read(); E[u].push_back(v), E[v].push_back(u); }
// 两次DFS求树直径 dfs(1); int c = 0; for (int i = 1; i <= n; ++i) { if (dep[c] < dep[i]) c = i; } dfs(c); c = 0; for (int i = 1; i <= n; ++i) { if (dep[c] < dep[i]) c = i; } int d = dep[c] - 1;
dfs(a);
// 计算答案 bool ans; if (dep[b] - 1 <= da) ans = 1; // 一步就死 elseif (da >= db) ans = 1; // A 的跳远更牛 elseif (d <= 2 * da) ans = 1; // A 全覆盖 elseif (db >= 2 * da + 1) ans = 0; // B 来回跳跃 else ans = 1; printf("%s\n", ans ? "Alice" : "Bob");
// 初始化 d = 0; for (int u = 1; u <= n; ++u) { E[u].clear(); } }