Atcoder Grand Contest 002 题解
A - Range Product
经过0答案肯定是0,都是正数肯定是正数,都是负数的话就奇负偶正。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int a, b; int main() { gii(a, b); if (a <= 0 && b >= 0) puts("Zero"); else { if (a > 0) puts("Positive"); else { if ((b - a + 1) & 1) puts("Negative"); else puts("Positive"); } } }
B - Box and Ball
模拟,顺序模拟判断用一个bool数组存这个点红球可不可能在这里,直接扫过去就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } const int N = 1e5 + 10; int n, m, x[N], y[N]; int cnt[N]; bool can[N]; int main() { gii(n, m); for (int i = 1; i <= m; ++i) gii(x[i], y[i]); for (int i = 1; i <= n; ++i) cnt[i] = 1; can[1] = 1; for (int i = 1; i <= m; ++i) { if (can[x[i]]) { if (cnt[x[i]] == 1) can[x[i]] = 0; can[y[i]] = 1; } --cnt[x[i]]; ++cnt[y[i]]; } int ans = 0; for (int i = 1; i <= n; ++i) if (can[i]) ++ans; printf("%d\n", ans); return 0; }
C - Knot Puzzle
找出最长的a[i]+a[i+1],如果大于等于l,就从两头一直删到这里,否则无解。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int a[100010]; int n, l; int main() { gii(n, l); for (int i = 1; i <= n; ++i) gi(a[i]); int j = 1; for (int i = 2; i < n; ++i) if (a[i] + a[i + 1] > a[j] + a[j + 1]) j = i; if (a[j] + a[j + 1] < l) { puts("Impossible"); return 0; } puts("Possible"); for (int i = 1; i < j; ++i) printf("%d\n", i); for (int i = n - 1; i >= j; --i) printf("%d\n", i); return 0; }
D - Stamp Rally
整体二分,用撤销并查集维护即可。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } const int N = 1e5 + 10; struct query { int x, y, z, id; }; int ans[N]; int n, m; int a[N], b[N]; struct info { int fa, siz; } f[N]; struct item { int x, y; info a, b; } stk[N]; int tp; int find(int x) { return f[x].fa == x ? x : find(f[x].fa); } void unit(int x, int y) { x = find(x), y = find(y); if (x == y) return; if (f[x].siz < f[y].siz) swap(x, y); stk[++tp] = (item) {x, y, f[x], f[y]}; f[y].fa = x, f[x].siz += f[y].siz; } void undo(int beg) { while (tp != beg) { f[stk[tp].x] = stk[tp].a; f[stk[tp].y] = stk[tp].b; --tp; } } void solve(int l, int r, vector<query> v) { if (l == r) { for (auto x : v) ans[x.id] = l; return; } int mid = (l + r) >> 1; int now = tp; for (int i = l; i <= mid; ++i) unit(a[i], b[i]); vector<query> L, R; L.clear(), R.clear(); for (auto x : v) { int siz = f[find(x.x)].siz; if (find(x.x) != find(x.y)) siz += f[find(x.y)].siz; if (siz >= x.z) L.pb(x); else R.pb(x); } solve(mid + 1, r, R); undo(now); solve(l, mid, L); } int main() { gii(n, m); for (int i = 1; i <= n; ++i) f[i] = (info) {i, 1}; for (int i = 1; i <= m; ++i) gii(a[i], b[i]); int Q; gi(Q); vector<query> v; v.clear(); for (int i = 1; i <= Q; ++i) { int x, y, z; giii(x, y, z); v.pb((query){x, y, z, i}); } solve(1, m, v); for (int i = 1; i <= Q; ++i) printf("%d\n", ans[i]); }
E - Candy Piles
把决策表画出来,我们发现一个人选择一种删除方式,另一个就选另一种,也就是沿着x=y的斜线走,最后只要有一个方向能让先手赢,先手肯定会走那一边,否则就是后手必胜。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int n, a[100010]; int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", a + i); sort(a + 1, a + n + 1); reverse(a + 1, a + n + 1); for (int i = 1; i <= n; ++i) { if (i + 1 > a[i + 1]) { int j = i + 1, ans = 0; for (; a[j] == i; ++j) ans ^= 1; if ((ans || ((a[i] - i) & 1))) puts("First"); else puts("Second"); break; } } }
F - Leftmost Ball
我们发现令白球的编号是1...n,保证编号小的在前面,只要算出这个方案数乘上n!,我们发现这是个特殊的拓扑图,求拓扑序方案数,一个n^2dp就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } const int mod = 1e9 + 7; int fpow(int a, int x) { int ret = 1; for (; x; x >>= 1) { if (x & 1) ret = 1LL * ret * a % mod; a = 1LL * a * a % mod; } return ret; } int f[2010][2010], n, k, fac[2010 * 2010], ifac[2010 * 2010]; int C(int n, int m) { if (n < m || m < 0) return 0; return 1LL * fac[n] * ifac[m] % mod * ifac[n - m] % mod; } int get(int x, int y) { return C(x + y, y); } int main() { gii(n, k); if (k == 1) { puts("1"); return 0; } f[0][0] = 1; fac[0] = 1; for (int i = 1; i <= (n + 2) * (k + 2); ++i) fac[i] = 1LL * fac[i - 1] * i % mod; ifac[(n + 2) * (k + 2)] = fpow(fac[(n + 2) * (k + 2)], mod - 2); for (int i = (n + 2) * (k + 2); i; --i) ifac[i - 1] = 1LL * ifac[i] * i % mod; for (int i = 0; i <= n; ++i) for (int j = i; j <= n; ++j) { if (i) f[i][j] = (f[i][j] + f[i - 1][j]) % mod; if (j) f[i][j] = (f[i][j] + 1LL * f[i][j - 1] * get((j - 1) * (k - 1) + i, k - 2)) % mod; //cerr << "get = " << get(j * (k - 1), k - 2) << endl; } printf("%d\n", int((1LL * f[n][n] * fac[n]) % mod)); return 0; }