正睿20NOIp前冲刺day8

估分:100+20+0+0=120

实际:100+20+0+0=120

T1:

  树形DP,f[i]表示以i为根的子树内所有点全遍历的最小花费,rev[i]表示遍历完子树所有点后回到i点需要的花废。dep[i]表示i的深度。设u的子节点有i,j,先遍历i,则有f[u]+=f[i],若rev[i]+1<dep[u],那遍历j的时候直接从i回到u再遍历j一定比传送回1节点再遍历到j优,则f[u]+=rev[i]+1+f[j]-dep[u]。所以f[u]先加上所有子节点的f,若有子节点i的rev+1<dep[u],那f[u]+=rev[i]+1-dep[u],但这样若所有字节点的rev+1都小于dep[u]的话会把所有的dep[u]全减掉,就会变成下图的样子:

 

 

  所以当这种情况时,记录一下rev最大的子节点的rev,最后再减掉,加上dep就行了。

  之后再看每个节点的rev应该是多少,可以发现,若当前节点i并不是所有子节点的rev+1都小于dep[i],那他一定不会往上走到父节点,而是直接传送回1号节点重新走到i的父节点u。因为若i不是所有子节点的rev+1都小于dep[i],那任意一个rev+1>=dep[i],若用这个rev回到u的话,他的花费一定是rev+2,一定是大于等于dep[u]的,所以肯定不用。所以只有i的所有子节点的rev+1全部都<dep[i]时,从i往回走到u才更优。这样DP就出来了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 1000010;
 8 const int INF = 0x3f3f3f3f;
 9 
10 int n;
11 int dep[N], f[N], rev[N];
12 int h[N], num[N << 1], nex[N << 1], dqx;
13 
14 void add(int a, int b)
15 {
16     num[dqx] = b;
17     nex[dqx] = h[a];
18     h[a] = dqx++;
19 }
20 
21 void dfs(int u, int pa)
22 {
23     int cnt = 0, res = 0;
24     for (int i = h[u]; ~i; i = nex[i])
25     {
26         int j = num[i];
27         if (j == pa) continue;
28         dep[j] = dep[u] + 1;
29         dfs(j, u);
30         f[u] = f[u] + f[j];
31         if (rev[j] + 1 <= dep[u])
32         {
33             f[u] += rev[j] + 1 - dep[u];
34             rev[u] = max(rev[u], rev[j] + 1);
35             cnt++;
36         }
37         res++;
38     }
39     if (cnt != res)  rev[u] = INF;
40     else f[u] += dep[u] - rev[u];
41     if (nex[h[u]] == -1 && u != 1) rev[u] = 0, f[u] = dep[u];
42 }
43 
44 int main()
45 {
46     scanf("%d", &n);
47     memset(h, -1, sizeof(h));
48     for (int i = 2; i <= n; i++)
49     {
50         int a;
51         scanf("%d", &a);
52         add(a, i), add(i, a);
53     }
54     dfs(1, 0);
55     printf("%d", f[1]);
56 }
View Code

T2:

  20pts暴力

  直接放题解,我说不清楚

 

 

 

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 5010;
 8 const int mod = 1e9 + 7;
 9 
10 int n, m;
11 int fac[N * 2], inv[N * 2], f[N][N], s[N];
12 
13 int C(int n, int m)
14 {
15     return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
16 }
17 
18 int qpow(int a, int k)
19 {
20     int res = 1;
21     while (k)
22     {
23         if (k & 1) res = 1ll * res * a % mod;
24         a = 1ll * a * a % mod;
25         k >>= 1;
26     }
27     return res;
28 }
29 
30 int main()
31 {
32     scanf("%d%d", &n, &m);
33 
34     fac[0] = inv[0] = 1;
35     for (int i = 1; i <= n + m; ++i)
36     {
37         fac[i] = 1ll * fac[i - 1] * i % mod;
38         inv[i] = qpow(fac[i], mod - 2);
39     }
40     for (int i = 1; i <= n; ++i)
41     {
42         for (int j = 1; i * j <= m; ++j)
43         {
44             for (int k = i, op = 1; k <= n && j * k <= m; ++k, op = mod - op)
45             {
46                 f[i][j] = (f[i][j] + 1ll * C(k, i) * op % mod * C(n, k) % mod * C(m - j * k + n - 1, n - 1)) % mod;
47             }
48             f[i][j] = 1ll * f[i][j] * qpow(C(m + n - 1, n - 1), mod - 2) % mod;
49         }
50     }
51 
52     for (int i = n; i >= 1; --i) 
53     {
54         s[i] = 1;
55         for (int j = 1; j <= m; ++j)
56         {
57             if ((f[i][j] += f[i + 1][j]) >= mod ) f[i][j] -= mod;
58             if ((s[i] += f[i][j]) >= mod ) s[i] -= mod;
59         }
60     }
61     for (int i = 1; i <= n; ++i)
62     {
63         if ((s[i] += s[i - 1]) >= mod) s[i] -= mod;
64         printf("%d\n", s[i]);
65     }
66 }
View Code

 

剩下两题不会

总结:

  没啥说的,菜是原罪

posted on 2020-10-21 21:53  ArrogHie  阅读(143)  评论(0编辑  收藏  举报