7.10洛谷多校4补

我在场上居然没过题,真是坑。

A

求树上两条从根出发的路径的并的点权异或和最大值。

n<=10^5

题解:

启发式合并+trie

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 100233;
 5 int n, a[N], fa[N], son[N], size[N];
 6 vector<int> G[N];
 7 
 8 void dfs1(int x, int pre) {
 9   fa[x] = pre;
10   size[x] = 1;
11   son[x] = 0;
12   for (auto y : G[x]) if (y != fa[x]) {
13     dfs1(y, x);
14     size[x] += size[y];
15     if (!son[x] || size[son[x]] < size[y]) {
16       son[x] = y;
17     }
18   }
19 }
20 
21 int pc = 1, ch[N * 40][2];
22 void clear() {
23   pc = 1;
24   ch[1][0] = ch[1][1] = 0;
25 }
26 void insert(int x) {
27   int cur = 1;
28   for (int i = 29; ~i; i--) {
29     if (!ch[cur][x >> i & 1]) {
30       ch[cur][x >> i & 1] = ++pc;
31       ch[pc][0] = ch[pc][1] = 0;
32     }
33     cur = ch[cur][x >> i & 1];
34   }
35 }
36 int ask(int x) {
37   if (pc == 1) return x;
38   int ans = 0, cur = 1;
39   for (int i = 29; ~i; i--) {
40     if (ch[cur][!(x >> i & 1)]) {
41       ans |= 1 << i;
42       cur = ch[cur][!(x >> i & 1)];
43     } else {
44       cur = ch[cur][x >> i & 1];
45     }
46   }
47   return ans;
48 }
49 
50 int answer = 0;
51 
52 void dfs3(int x, int cur) {
53   answer = max(answer, ask(cur));
54   for (auto y : G[x]) if (y != fa[x]) {
55     dfs3(y, cur ^ a[y]);
56   }
57 }
58 void dfs4(int x, int cur) {
59   insert(cur);
60   for (auto y : G[x]) if (y != fa[x]) {
61     dfs4(y, cur ^ a[y]);
62   }
63 }
64 
65 void dfs2(int x, int cur, bool keep) {
66   answer = max(answer, cur);
67   for (auto y : G[x]) if (y != fa[x] && y != son[x]) {
68     dfs2(y, cur ^ a[y], false);
69   }
70   if (son[x]) {
71     dfs2(son[x], cur ^ a[son[x]], true);
72   } else {
73     clear();
74   }
75   for (auto y : G[x]) if (y != fa[x] && y != son[x]) {
76     dfs3(y, a[y]);
77     dfs4(y, cur ^ a[y]);
78   }
79   if (keep) {
80     insert(cur);
81   } else {
82     clear();
83   }
84 }
85 
86 int main() {
87   scanf("%d", &n);
88   for (int i = 1; i <= n; i++) {
89     scanf("%d", &a[i]);
90   }
91   for (int i = 1, x, y; i < n; i++) {
92     scanf("%d%d", &x, &y);
93     G[x].push_back(y);
94     G[y].push_back(x);
95   }
96   dfs1(1, 0);
97   dfs2(1, a[1], false);
98   printf("%d\n", answer);
99 }

B

网格上有一些颜色,每次删除一种颜色,若某种颜色不与其他任何还留在网格上的颜色相邻,这种颜色也会消失,问期望多少次删除能使所有颜色消失。

n,m<=1000 颜色数C<=10^6

题解:

把颜色看成点建图,有相邻则连边一条。

问题变成了,删除一个点,与该点相连的边都会消失,新生成的孤立点也消失,问期望删除点数。

一个点只有被直接删除了才会产生1的贡献,因其他点的删除而消失不会对答案产生贡献,因此需要计算一个点被删除的概率。

一个点被删除的概率=1-不被删除的概率。

一个点不被删除,只有它身边的所有点都被删除了,且自己没被删除,这个概率=d[x]/(d[x]+1) * (d[x]-1)/d[x] * ......*1/2=1/(d[x]+1),d[x]为x的度数。

所以答案为C-∑1/(d[x]+1)

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e6+10,mod=1e9+7;
 4 int n,m,C,a[1010][1010];
 5 set<int> st[maxn];
 6 int qpow(int a,int b){
 7     int ans=1;
 8     for(;b;b>>=1,a=1ll*a*a%mod)
 9         if(b&1)ans=1ll*ans*a%mod;
10     return ans;
11 }
12 int main(){
13     scanf("%d%d%d",&n,&m,&C);
14     int mn=1e9,mx=-1e9;
15     for(int i=1;i<=n;++i)
16         for(int j=1;j<=m;++j)
17             scanf("%d",&a[i][j]),mn=min(mn,a[i][j]),mx=max(mx,a[i][j]);
18     for(int i=1;i<=C;++i)st[i].insert(i);
19     for(int i=1;i<=n;++i)
20         for(int j=1;j<=m;++j){
21             if(i>1)st[a[i][j]].insert(a[i-1][j]);
22             if(i<n)st[a[i][j]].insert(a[i+1][j]);
23             if(j>1)st[a[i][j]].insert(a[i][j-1]);
24             if(j<m)st[a[i][j]].insert(a[i][j+1]);
25         }
26     int ans=0;
27     for(int i=1;i<=C;++i)ans=(ans+qpow(st[i].size(),mod-2))%mod;
28     if(mn==mx)printf("1\n");
29     else printf("%d\n",(C-ans+mod)%mod);
30 }

 

posted @ 2021-07-10 18:40  praying_cqf  阅读(39)  评论(0编辑  收藏  举报