1. 程式人生 > 其它 >7.10洛谷多校4補

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 }