正睿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:

  不会

  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 }
View Code

 

 

总结:

  关于数论的东西还不熟,数学期望还要回去多看看;第二题是没想到这个思路,光想着排序从大选到小去了;第三题想着计算上下限了,没想着二分答案;第四题是真不会,DP感觉还是想不出。

  在考场上还是想不到正解,考试经验还是不大足,还得多考多练

  

posted on 2020-09-15 07:54  ArrogHie  阅读(206)  评论(0)    收藏  举报