AtCoder Grand Contest 009 题解
A - Multiple Array
倒着算要加多少就好了。
//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; long long a[N], b[N]; int main() { gi(n); for (int i = 1; i <= n; ++i) gii(a[i], b[i]); long long add = 0; for (int i = n; i; --i) { a[i] += add; if (a[i] % b[i]) add += b[i] - a[i] % b[i], a[i] += b[i] - a[i] % b[i]; } printf("%lld\n", add); return 0; }
B - Tournament
树形dp,把所有儿子的轮数从小到大排序,算一下自己最少要多少轮即可。
//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]; VI edge[100010]; int rd[100010]; void dfs(int u) { VI p; for (auto v : edge[u]) { dfs(v); p.pb(rd[v]); } sort(ALL(p)); for (auto x : p) rd[u] = max(rd[u], x), ++rd[u]; } int main() { gi(n); for (int i = 2; i <= n; ++i) gi(a[i]), edge[a[i]].pb(i); dfs(1); printf("%d\n", rd[1]); return 0; }
C - Division into Two
列出dp方程,令A>=B,把可以取的位置丢进树状数组维护一下dp即可。
//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, mod = 1e9 + 7; int n; int64 A, B, S[N]; int lf[N], f[N], g[N]; int t[N]; void add(int x, int v) { for (++x; x <= n + 1; x += x & -x) t[x] = (t[x] + v) % mod; } int query(int x) { int v = 0; for (++x; x; x -= x & -x) v = (v + t[x]) % mod; return v; } int main() { gi(n); scanf("%lld%lld", &A, &B); if (A < B) swap(A, B); for (int i = 1; i <= n; ++i) scanf("%lld", S + i); S[0] = -A; ++n; S[n] = S[n - 1] + A; lf[1] = 1; for (int i = 2; i <= n; ++i) if (S[i] >= S[i - 1] + B) lf[i] = lf[i - 1]; else lf[i] = i; f[0] = 1; add(0, f[0]); for (int i = 1; i <= n; ++i) { int k = upper_bound(S + 1, S + i + 1, S[i] - A) - S - 1; int j = lf[i - 1] - 1; if (S[i] - S[i - 1] >= A) f[i] = f[i - 1]; if (i >= 2 && min(i - 2, k) >= j - 1) (f[i] += (query(min(i - 2, k)) - query(j - 1) + mod) % mod) %= mod; if (i < n && S[i + 1] - S[i - 1] >= B) add(i, f[i]); } printf("%d\n", f[n]); return 0; }
D - Uninity
树分治是上界,也就是log,当有两个点是第k次标号,中间肯定要有一个k+1,用这个进行dp,算一下每个点的所有儿子令它最大是多少就好了。
//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; VI edge[N]; int n, bit[N], f[N]; void dfs(int u, int fa) { int l = 0; for (auto v : edge[u]) { if (v == fa) continue; dfs(v, u); l |= bit[u] & bit[v]; bit[u] |= bit[v]; } if (!bit[u]) bit[u] = 1; else { while ((1 << f[u]) < l || ((1 << f[u]) & bit[u])) ++f[u]; bit[u] = ((bit[u] >> f[u]) << f[u]) | (1 << f[u]); } f[0] = max(f[0], f[u]); } int main() { gi(n); for (int i = 1; i < n; ++i) { int u, v; gii(u, v); edge[u].pb(v); edge[v].pb(u); } dfs(1, 0); printf("%d\n", f[0]); return 0; }
E - Eternal Average
转换为k叉树模型,发现最后要求的是一个符合条件序列的个数,dp一下即可。
//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 n, m, k, ans; int f[2][2010][2], sum[2010]; int main() { giii(n, m, k); --m, --k; for (int i = 1; i <= k; ++i) f[0][i][1] = 1; f[0][0][0] = 1; for (int i = 0; i <= n; ++i) if (k - i <= m && i % k == n % k && (k - i) % k == m % k) ans = (ans + f[0][i][1]) % mod; int now = 0; for (int i = 2; i <= max(n, m) * 2; ++i) { now ^= 1; for (int j = 0; j <= n; ++j) sum[j + 1] = (sum[j] + (f[now ^ 1][j][0] + f[now ^ 1][j][1]) % mod) % mod; for (int j = 0; j <= n; ++j) { f[now][j][0] = (sum[j + 1] - sum[j] + mod) % mod; f[now][j][1] = (sum[j] - sum[max(0, j - k)] + mod) % mod; } for (int j = 0; j <= n; ++j) if (k * i - j <= m && j % k == n % k && (k * i - j) % k == m % k) ans = (ans + f[now][j][1]) % mod; //cerr << ans << endl; } printf("%d\n", ans); }