A – 吴国十分危险
他妈看错题,啊,心态崩了。(虽然看对了都不一定能推出结论)。
// A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 110; int T, n, k, siz[MAX_N]; vector<int> G[MAX_N]; bool flag; void dfs(int u, int fa) { siz[u] = 1; int leaf = 0; for (int v : G[u]) if (v != fa) { dfs(v, u), siz[u] += siz[v]; if (siz[v] == 1) leaf++; } if (leaf >= 2) flag = true; } void cut(int u, int fa) { siz[u] = 1; for (int v : G[u]) if (v != fa) { cut(v, u); if (siz[v] == 2) siz[v] = 0, k--; siz[u] += siz[v]; } if (siz[u] > 2) flag = true; } int main() { scanf("%d", &T); while (T--) { scanf("%d%d", &n, &k), flag = false; for (int i = 1; i <= n; i++) G[i].clear(), siz[i] = 0; for (int i = 1, u, v; i <= n - 1; i++) scanf("%d%d", &u, &v), G[u].push_back(v), G[v].push_back(u); if (n % 2 == 1) { puts("Alice"); continue; } if (n == 2) { puts("Bob"); continue; } dfs(1, 0), cut(1, 0); if (flag || k < 0 || siz[1] != 2) puts("Alice"); else puts("Bob"); } return 0; }
B – 董先生的钦定
先不考虑剔除空集的情况,对于每一个非空集合而言,其补集和该集合本身至少有一个数量和大于全集的一半,知道这个之后就发现这个东西一一对应,所以对于没有空集的情况而言,答案就是 \( \frac{S}{2} \),其中 \(S\) 是全集和。对于没有空集的情况,那肯定稍大,考虑 DP 出来然后找附近的即可。
// B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 2020; int n, ai[MAX_N], m; bitset<MAX_N * MAX_N> f; int main() { scanf("%d", &n), f[0] = 1; for (int i = 1; i <= n; i++) scanf("%d", &ai[i]), m += ai[i], f = f | (f << ai[i]); m = (m + 1) >> 1; for (int i = 1; i <= n * n; i++) if (i >= m && f[i]) printf("%d\n", i), exit(0); return 0; }
C – 超越潜能
我们可以考虑维护前缀和和后缀和。对于指针向右的情况,我们只需要维护从左到右的前缀和和贡献和即可;对于指针向左的情况,我们需要维护后缀和和线段树,我们可以通过后缀和和前缀和来算这个 \(0\) 的窗口位置,用线段树来维护一条条线段,询问时只需要找到 \(0\) 的绝对位置。
// C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 3e5 + 200, INF = 1e9; int n, m, ptot; char cmdlet[10]; struct node { int lson, rson, tag; } nodes[MAX_N * 120]; #define mid ((l + r) >> 1) int update(int ql, int qr, int l, int r, int pre) { int p = ++ptot; nodes[p] = nodes[pre]; if (ql <= l && r <= qr) return nodes[p].tag++, p; if (ql <= mid) nodes[p].lson = update(ql, qr, l, mid, nodes[pre].lson); if (mid < qr) nodes[p].rson = update(ql, qr, mid + 1, r, nodes[pre].rson); return p; } int query(int qx, int l, int r, int p) { if (p == 0) return 0; int ret = nodes[p].tag; if (l == r) return ret; if (qx <= mid) ret += query(qx, l, mid, nodes[p].lson); else ret += query(qx, mid + 1, r, nodes[p].rson); return ret; } struct axisManager { int ptr, org[MAX_N], roots[MAX_N], pre[MAX_N], pre_prod[MAX_N], suf[MAX_N]; void moveLeft() { if (ptr == 1) return; roots[ptr] = roots[ptr + 1], suf[ptr] = suf[ptr + 1] + org[ptr]; int lft = min(suf[ptr] - org[ptr], suf[ptr]), rig = max(suf[ptr] - org[ptr], suf[ptr]); roots[ptr] = update(lft, rig, -INF, INF, roots[ptr]), ptr--; } void moveRight() { if (ptr == n) return; ptr++; pre[ptr] = pre[ptr - 1] + org[ptr]; pre_prod[ptr] = pre_prod[ptr - 1] + ((pre[ptr] > 0) ^ (pre[ptr - 1] > 0)); } void build() { ptr = 0, org[0] = pre[0] = 1; for (int i = 1; i <= n; i++) moveRight(); for (int i = n; i > 1; i--) moveLeft(); } void updateOnAxis(int d) { org[ptr] = d, pre[ptr] = pre[ptr - 1] + org[ptr]; pre_prod[ptr] = pre_prod[ptr - 1] + ((pre[ptr] > 0) ^ (pre[ptr - 1] > 0)); } int queryOnAxis() { return query(pre[ptr] + suf[ptr + 1], -INF, INF, roots[ptr + 1]) + pre_prod[ptr]; } } dr[2]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d%d", &dr[0].org[i], &dr[1].org[i]); dr[0].build(), dr[1].build(), scanf("%d", &m); while (m--) { scanf("%s", cmdlet + 1); if (cmdlet[1] == 'B') dr[0].moveLeft(), dr[1].moveLeft(); else if (cmdlet[1] == 'C') { int nx, ny; scanf("%d%d", &nx, &ny); dr[0].updateOnAxis(nx), dr[1].updateOnAxis(ny); } else if (cmdlet[1] == 'F') dr[0].moveRight(), dr[1].moveRight(); else if (cmdlet[1] == 'Q') printf("%d\n", dr[0].queryOnAxis() + dr[1].queryOnAxis()); } return 0; }