正睿20秋季普转提day2
估分:0+80+60+0=140
实际:0+80+30+0=110
T1:
不会,不知道怎么算他的数学期望
每个点每次被覆盖的概率是1/size,size是他的子树大小,因为期望有线性性,最后把所有点的概率加起来就是答案。逆元用线性求,不然会超时。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 const int N = 10000010; 8 const int mod = 998244353; 9 10 int n; 11 int siz[N], pa[N], inv[N]; 12 13 inline int read() 14 { 15 int x = 0, f = 0; 16 char ch = getchar(); 17 while (!isdigit(ch)) f = ch == '-', ch = getchar(); 18 while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); 19 return f ? -x : x; 20 } 21 22 int main() 23 { 24 n = read(); 25 siz[1] = 1; 26 for (int i = 2; i <= n; i++) 27 { 28 siz[i] = 1; 29 pa[i] = read(); 30 } 31 32 inv[1] = 1; 33 for (int i = 2; i <= n; i++) 34 { 35 inv[i] = (long long)(mod - (mod / i)) * inv[mod % i] % mod; 36 } 37 int ans = 0; 38 for (int i = n; i; i--) 39 { 40 ans = (long long)(ans + inv[siz[i]]) % mod; 41 siz[pa[i]] += siz[i]; 42 } 43 printf("%d", ans); 44 }
T2:
不会,打了80pts暴力
如果n是偶数就随便拿一个使n变成奇数,当n是奇数时,将糖果按a从大到小排序,先拿掉a最大的糖果,在把剩下的糖果每相邻两个一组,每组选b较大的一个,就是答案。可以容易证明出这样做一定有解。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 8 const int N = 100010; 9 10 int n; 11 vector<int> ans; 12 13 struct Node 14 { 15 int a, b, id; 16 Node() {} 17 }; 18 19 Node s[N]; 20 21 bool cmp(Node a, Node b) 22 { 23 return a.a > b.a; 24 } 25 26 int main() 27 { 28 scanf("%d", &n); 29 for (int i = 1; i <= n; i++) scanf("%d", &s[i].a); 30 for (int i = 1; i <= n; i++) scanf("%d", &s[i].b), s[i].id = i; 31 sort(s + 1, s + 1 + n, cmp); 32 bool flag = false; 33 if (n % 2 == 0) ans.push_back(s[n].id), n--, flag = true; 34 ans.push_back(s[1].id); 35 for (int i = 2; i <= n; i+=2) 36 { 37 ans.push_back(s[i].b > s[i + 1].b ? s[i].id : s[i + 1].id); 38 } 39 40 if (flag) n++; 41 printf("%d\n", n / 2 + 1); 42 for (auto i : ans) 43 { 44 printf("%d ", i); 45 } 46 }
T3:
不会,打了30pts的暴力和30pts的B=0的情况,然而暴力思路不大对
二分答案,求出每个节点子树中黑点个数的上限和下限,看是否合法。每个节点的上限为min(子节点的上限和,总节点数-当前节点的B限制),每个节点的下限为max(子节点的下限和,当前节点A限制)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 #define int long long 8 9 const int N = 100010; 10 11 int n; 12 int k[N]; 13 int limA[N], limB[N]; 14 int down[N], up[N]; 15 int h[N], num[N << 1], nex[N << 1], dqx; 16 17 void add(int a, int b) 18 { 19 num[dqx] = b; 20 nex[dqx] = h[a]; 21 h[a] = dqx++; 22 } 23 24 void dfs(int u, int fa) 25 { 26 down[u] = 0, up[u] = 1; 27 for (int i = h[u]; ~i; i = nex[i]) 28 { 29 int j = num[i]; 30 if (j == fa) continue; 31 dfs(j, u); 32 if (down[j] > up[j]) 33 { 34 down[u] = 0, up[u] = -1; 35 return; 36 } 37 down[u] += down[j], up[u] += up[j]; 38 } 39 down[u] = max(down[u], limA[u]); 40 up[u] = min(up[u], k[u]); 41 } 42 43 bool check(int x) 44 { 45 for (int i = 1; i <= n; i++) 46 { 47 k[i] = x - limB[i]; 48 if (k[i] < limA[i]) return false; 49 } 50 51 dfs(1, 0); 52 if (down[1] > x || up[1] < x) return false; 53 return true; 54 } 55 56 signed main() 57 { 58 scanf("%lld", &n); 59 memset(h, -1, sizeof(h)); 60 for (int i = 1; i < n; i++) 61 { 62 int a, b; 63 scanf("%lld%lld", &a, &b); 64 add(a, b), add(b, a); 65 } 66 67 int m; 68 69 scanf("%lld", &m); 70 for (int i = 1; i <= m; i++) 71 { 72 int x, a; 73 scanf("%lld%lld", &x, &a); 74 limA[x] = max(limA[x], a); 75 } 76 77 scanf("%lld", &m); 78 for (int i = 1; i <= m; i++) 79 { 80 int x, a; 81 scanf("%lld%lld", &x, &a); 82 limB[x] = max(limB[x], a); 83 } 84 85 int l = 0, r = n + 1; 86 while (l < r) 87 { 88 int mid = (l + r) >> 1; 89 if (check(mid)) r = mid; 90 else l = mid + 1; 91 } 92 93 if (r > n) puts("-1"); 94 else printf("%lld", r); 95 }
T4:
不会
f1[k][i],f2[k][i]分别表示当前重链从1走到x,Alice分数为i和Bob的分数为i的方案数,g1[x][i]和 g2[x][i]表示x子树内,Alice 最多拿 i 分和 Bob 最多 拿 i 分的方案数,允许在另一个人不改变方案的前提下任意改变方案。DP公式太难讲,写在代码里。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 8 typedef long long LL; 9 10 const int N = 5010; 11 const int mod = 998244353; 12 13 int n, m; 14 int fa[N], son[N]; 15 int f1[N][N], f2[N][N], g1[N][N], g2[N][N], bin[N]; 16 17 vector<int> v[N]; 18 19 inline int read() 20 { 21 int x = 0; char ch = getchar(); 22 for (; ch < '0' || ch>'9'; ch = getchar()); 23 for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; 24 return x; 25 } 26 27 inline int pls(int x, int y) 28 { 29 return (x + y < mod) ? x + y : x + y - mod; 30 } 31 32 inline void dfs1(int x, int y) 33 { 34 if (!son[x]) 35 { 36 for (int i = 1; i <= m; i++) f1[x][i] = f2[x][i] = i * m; 37 bin[x] = m * m; 38 return; 39 } 40 int t1 = v[x][0], t2 = v[x][1]; 41 dfs1(t1, y ^ 1); dfs1(t2, y ^ 1); 42 bin[x] = (LL)bin[t1] * bin[t2] * 2 % mod; 43 if (!y) 44 { 45 for (int i = 1; i <= m; i++) f1[x][i] = (LL)f1[t1][i] * f1[t2][i] % mod * 2 % mod; 46 for (int i = 1; i <= m; i++) f2[x][i] = pls((LL)f2[t1][i] * bin[t2] % mod, (LL)f2[t2][i] * bin[t1] % mod); 47 } 48 else 49 { 50 for (int i = 1; i <= m; i++) f2[x][i] = (LL)f2[t1][i] * f2[t2][i] % mod * 2 % mod; 51 for (int i = 1; i <= m; i++) f1[x][i] = pls((LL)f1[t1][i] * bin[t2] % mod, (LL)f1[t2][i] * bin[t1] % mod); 52 } 53 } 54 55 int ans = 0; 56 57 inline void dfs2(int x, int y) 58 { 59 if (!son[x]) 60 { 61 int s1 = 0, s2 = 0; 62 for (int i = 1; i <= m; i++) s1 = pls(s1, g1[x][i]), s2 = pls(s2, g2[x][i]); 63 ans = pls(ans, (LL)s1 * s2 % mod); 64 return; 65 } 66 int t1 = v[x][0], t2 = v[x][1]; 67 if (!y) 68 { 69 for (int i = 1; i <= m; i++) g1[t1][i] = (LL)g1[x][i] * f1[t2][i] % mod, g1[t2][i] = (LL)g1[x][i] * f1[t1][i] % mod; 70 for (int i = 1; i <= m; i++) g2[t1][i] = g2[x][i], g2[t2][i] = g2[x][i]; 71 } 72 else 73 { 74 for (int i = 1; i <= m; i++) g2[t1][i] = (LL)g2[x][i] * f2[t2][i] % mod, g2[t2][i] = (LL)g2[x][i] * f2[t1][i] % mod; 75 for (int i = 1; i <= m; i++) g1[t1][i] = g1[x][i], g1[t2][i] = g1[x][i]; 76 } 77 dfs2(t1, y ^ 1); 78 dfs2(t2, y ^ 1); 79 } 80 81 int main() 82 { 83 n = read(), m = read(); 84 for (int i = 2; i <= n; i++) v[fa[i] = read()].push_back(i), son[fa[i]]++; 85 86 dfs1(1, 0); 87 88 for (int i = 1; i <= m; i++) g1[1][i] = g2[1][i] = 1; 89 90 dfs2(1, 0); 91 92 printf("%lld\n", ans); 93 }
总结:
关于数论的东西还不熟,数学期望还要回去多看看;第二题是没想到这个思路,光想着排序从大选到小去了;第三题想着计算上下限了,没想着二分答案;第四题是真不会,DP感觉还是想不出。
在考场上还是想不到正解,考试经验还是不大足,还得多考多练
浙公网安备 33010602011771号