FJ省队集训最终测试 T2
思路:发现如果一个人一共选了x个点,那么选中某一个点对的概率都是一样的,一个人选x个点的总方案是C(n,x),一个人选中某个点对的总方案是C(n-2,x-2),这样,那么选中某个点对的概率就是 x*(x-1)/(n*(n-1)),这样,我们就用树分治求出有多少对符合条件的对数,然后乘上每个人的概率即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define inf 0x7fffffff 7 int son[200005],F[200005],root,vis[200005],pd[200005],c[200005]; 8 int n,go[200005],tot,first[200005],next[200005],dis[200005],num,sz,m,b[200005]; 9 int ans,cnt[200005]; 10 double Ans; 11 int read(){ 12 int t=0,f=1;char ch=getchar(); 13 while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 14 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 15 return t*f; 16 } 17 void insert(int x,int y){ 18 tot++; 19 go[tot]=y; 20 next[tot]=first[x]; 21 first[x]=tot; 22 } 23 void add(int x,int y){ 24 insert(x,y);insert(y,x); 25 } 26 void findroot(int x,int fa){ 27 son[x]=1;F[x]=0; 28 for (int i=first[x];i;i=next[i]){ 29 int pur=go[i]; 30 if (vis[pur]||pur==fa) continue; 31 findroot(pur,x); 32 son[x]+=son[pur]; 33 F[x]=std::max(F[x],son[pur]); 34 } 35 F[x]=std::max(F[x],num-son[x]); 36 if (F[x]<F[root]) root=x; 37 } 38 void bfs(int x){ 39 int h=1,t=1;c[h]=x;pd[x]=sz;dis[x]=1; 40 while (h<=t){ 41 int now=c[h++]; 42 for (int i=first[now];i;i=next[i]){ 43 int pur=go[i]; 44 if (vis[pur]||pd[pur]) continue; 45 pd[pur]=sz; 46 dis[pur]=dis[now]+1; 47 c[++t]=pur; 48 } 49 } 50 for (int j=1;j<=m;j++) 51 for (int i=1;i<=t;i++) 52 if (b[j]>=dis[c[i]]) 53 ans+=cnt[b[j]-dis[c[i]]]; 54 for (int i=1;i<=t;i++) 55 cnt[dis[c[i]]]++; 56 } 57 void solve(int x,int fa){ 58 vis[x]=1;sz++; 59 memset(cnt,0,sizeof cnt);cnt[0]=1; 60 for (int i=first[x];i;i=next[i]){ 61 int pur=go[i]; 62 if (vis[pur]) continue; 63 bfs(pur); 64 } 65 int Sum=num; 66 for (int i=first[x];i;i=next[i]){ 67 int pur=go[i]; 68 if (vis[pur]) continue; 69 if (son[pur]>son[x]) num=Sum-son[x]; 70 else num=son[pur]; 71 root=0; 72 findroot(pur,0); 73 solve(root,x); 74 } 75 } 76 int main(){ 77 n=read();m=read(); 78 for (int i=1;i<=m;i++){ 79 b[i]=read(); 80 } 81 std::sort(b+1,b+1+m); 82 for (int i=1;i<n;i++){ 83 int u=read(),v=read(); 84 add(u,v); 85 } 86 F[0]=inf;root=0;num=n; 87 findroot(1,0); 88 solve(root,0); 89 double Ans=(((double)ans)/((double)n))/((double)n-1); 90 int m=n/3; 91 if (n%3) printf("%.2lf\n",Ans*(m+1)*(m)); 92 else printf("%.2lf\n",Ans*(m-1)*m); 93 if (n%3==2) printf("%.2lf\n",Ans*(m+1)*(m)); 94 else printf("%.2lf\n",Ans*(m-1)*m); 95 printf("%.2lf\n",Ans*(m-1)*m); 96 }