【BZOJ4675】點對遊戲 樹分治+期望
阿新 • • 發佈:2017-10-15
三人 hellip 小數 tro 統計 int 多少 microsoft 題解
第一行兩個整數n、m,分別表示樹的節點數和幸運數的數目。
第二行m個互異正整數,表示m個幸運數。
以下n-1行,每行兩個整數u、v,表示節點u和節點v之間有邊。節點從1
到n編號。
3 <= n <= 50000, m <= 10,幸運數大小 <= n
1 3
1 2
1 5
2 3
2 4
0.60
0.00
【BZOJ4675】點對遊戲
Description
桑尼、露娜和斯塔在玩點對遊戲,這個遊戲在一棵節點數為n的樹上進行。 桑尼、露娜和斯塔三人輪流從樹上所有未被占有的節點中選取一點,歸為己有,輪流順序為桑尼、露娜、斯塔、桑尼、露娜……。該選取過程直到樹上所有點都被選取後結束。 選完點後便可計算每人的得分。點對遊戲中有m個幸運數,在某人占據的節點中,每有一對點的距離為某個幸運數,就得到一分。(樹上兩點之間的距離定義為兩點之間的簡單路徑的邊數) 你的任務是,假設桑尼、露娜和斯塔每次選取時,都是從未被占有的節點中等概率選取一點,計算每人的期望得分。Input
Output
三行實數,分別表示桑尼、露娜和斯塔的期望得分,保留兩位小數。Sample Input
5 21 3
1 2
1 5
2 3
2 4
Sample Output
0.600.60
0.00
題解:本題的做法比較神。
先用點分治統計出所有幸運點對的個數,然後分別統計每個人都選出了多少個點對,用選出的點對數*幸運點對數/總點對數 即是答案。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=50010; int sum; int n,m,cnt,rt,mn,tot; int to[maxn<<1],next[maxn<<1],head[maxn],dep[maxn],vis[maxn],siz[maxn],luck[20],f[maxn],g[maxn],md[maxn]; double ans[maxn],s[maxn]; void getrt(int x,int fa) { siz[x]=1; int tmp=0; for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa&&!vis[to[i]]) getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]); tmp=max(tmp,tot-siz[x]); if(tmp<mn) mn=tmp,rt=x; } void getmd(int x,int fa,int dep) { siz[x]=1,md[x]=0; for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa&&!vis[to[i]]) getmd(to[i],x,dep+1),siz[x]+=siz[to[i]],md[x]=max(md[x],md[to[i]]+1); } void getdep(int x,int fa,int dep) { g[dep]++; for(int i=1;i<=m;i++) if(dep<=luck[i]) sum+=f[luck[i]-dep]; for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa&&!vis[to[i]]) getdep(to[i],x,dep+1); } void dfs(int x) { vis[x]=1; getmd(x,0,0); f[0]=1; for(int i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]) { getdep(to[i],x,1); for(int j=0;j<=md[to[i]]+1;j++) f[j]+=g[j],g[j]=0; } memset(f,0,sizeof(f[0])*(md[x]+2)); for(int i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]) tot=siz[to[i]],mn=1<<30,getrt(to[i],x),dfs(rt); } inline void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { //freopen("game0.in","r",stdin); //freopen("game.out","w",stdout); n=rd(),m=rd(); int i,a,b; for(i=1;i<=m;i++) luck[i]=rd(); memset(head,-1,sizeof(head)); for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a); tot=n,mn=1<<30,getrt(1,0),dfs(rt); a=(n+2)/3,printf("%.2lf\n",1.0*a*(a-1)*sum/(1.0*n*(n-1))); a=(n+1)/3,printf("%.2lf\n",1.0*a*(a-1)*sum/(1.0*n*(n-1))); a=n/3,printf("%.2lf\n",1.0*a*(a-1)*sum/(1.0*n*(n-1))); return 0; }
【BZOJ4675】點對遊戲 樹分治+期望