7.10洛谷多校4補
阿新 • • 發佈:2021-07-10
我在場上居然沒過題,真是坑。
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 }