正睿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 }View Code
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 }View Code
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 }View Code
T4:
不会
现在依然不会
总结:
关于数论的东西还不熟,数学期望还要回去多看看;第二题是没想到这个思路,光想着排序从大选到小去了;第三题想着计算上下限了,没想着二分答案;第四题是真不会。
在考场上还是想不到正解,考试经验还是不大足,还得多考多练
标签:ch,普转,int,up,down,正睿,20,include,节点 来源: https://www.cnblogs.com/Arrogant-Hierarch/p/13670934.html