(WC2018模拟十二)【FJOI2016集训Day7T2】点对游戏

题解:

还好。。。看懂题目就好做了。(Orzdyh)

首先选择的点是等概率随机的,也就是说每种选择结果的概率都是一样的,所以选择一个点的时候已经选择的点不会有影响,那么就可以直接算出点对个数再求总体的期望。具体来说,每条边会在$\binom{n-2}{\lceil\frac{n}{3}\rceil -1}$种情况中被选择(说不清楚,感性理解一下),再除以总的情况数$\binom{n}{\lceil\frac{n}{3}\rceil}$即可,这一步可以约分,注意要对$n\mod 3$的余数分类讨论。

前面的部分是点分治经典应用,就不说了。我貌似写的很挫,第一次有三个点T了20ms,其他人一共就跑了20ms。。。第二次加了读入优化999ms过了。。。妙不可言

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7 #define inf 2147483647
  8 #define eps 1e-9
  9 using namespace std;
 10 typedef long long ll;
 11 struct edge{
 12     int v,next;
 13 }a[100001];
 14 int n,m,u,v,lk[11],anss[11],sum=0,S,rt,tot=0,cnt=0,head[50001],siz[50001],mx[50001],dis[50001];
 15 bool used[50001];
 16 double ans1,ans2;
 17 char buffer[1000010],*hd,*tl;
 18 inline char Getchar(){
 19     if(hd==tl){
 20         int len=fread(buffer,1,1000000,stdin);
 21         hd=buffer,tl=hd+len;
 22         if(hd==tl)
 23             return EOF;
 24     }
 25     return *hd++;
 26 }
 27 inline int rd(){
 28     register int x=0;
 29     char c;
 30     do c=Getchar();
 31     while(!isdigit(c));
 32     do{
 33         x=(x<<1)+(x<<3)+(c^48);
 34         c=Getchar();
 35     }while(isdigit(c));
 36     return x;
 37 }
 38 inline void add(int u,int v){
 39     a[++tot].v=v;
 40     a[tot].next=head[u];
 41     head[u]=tot;
 42 }
 43 inline void dfsrt(int u,int ff){
 44     siz[u]=1;
 45     mx[u]=0;
 46     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
 47         int v=a[tmp].v;
 48         if(v!=ff&&!used[v]){
 49             dfsrt(v,u);
 50             mx[u]=max(mx[u],siz[v]);
 51             siz[u]+=siz[v];
 52         }
 53     }
 54     mx[u]=max(mx[u],S-siz[u]);
 55     if(mx[u]<mx[rt])rt=u;
 56 }
 57 inline void getdis(int u,int fa,int ds){
 58     dis[++cnt]=ds;
 59     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
 60         int v=a[tmp].v;
 61         if(v!=fa&&!used[v])getdis(v,u,ds+1);
 62     }
 63 }
 64 inline int gao1(int l,int r,int k){
 65     int ret=-1;
 66     while(l<=r){
 67         int mid=(l+r)/2;
 68         if(dis[mid]==k)ret=mid,l=mid+1;
 69         else if(dis[mid]<k)l=mid+1;
 70         else r=mid-1;
 71     }
 72     return ret;
 73 }
 74 inline int gao2(int l,int r,int k){
 75     int ret=0;
 76     while(l<=r){
 77         int mid=(l+r)/2;
 78         if(dis[mid]==k)ret=mid,r=mid-1;
 79         else if(dis[mid]<k)l=mid+1;
 80         else r=mid-1;
 81     }
 82     return ret;
 83 }
 84 inline int calc(int u,int w,int K){
 85     cnt=0;
 86     getdis(u,0,w);
 87     sort(dis+1,dis+cnt+1);
 88     //for(int i=1;i<=cnt;i++)printf("%d ",dis[i]);
 89     //printf("\n");
 90     int ret=0;
 91     for(int i=1;i<=cnt;i++){
 92         if(dis[i]*2>K)break;
 93         ret+=gao1(i,cnt,K-dis[i])-gao2(i,cnt,K-dis[i])+1;
 94     }
 95     return ret;
 96 }
 97 inline void divide(int u){
 98     used[u]=true;
 99     for(int i=1;i<=m;i++)anss[i]+=calc(u,0,lk[i]);
100     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
101         int v=a[tmp].v;
102         if(!used[v]){
103             for(int i=1;i<=m;i++){
104                 anss[i]-=calc(v,1,lk[i]);
105             }
106             S=siz[v],rt=0;
107             dfsrt(v,0);
108             divide(rt);
109         }
110     }
111 }
112 int main(){
113     memset(head,-1,sizeof(head));
114     memset(anss,0,sizeof(anss));
115     //scanf("%d%d",&n,&m);
116     n=rd(),m=rd();
117     for(int i=1;i<=m;i++)lk[i]=rd();//scanf("%d",&lk[i]);
118     for(int i=1;i<n;i++){
119         //scanf("%d%d",&u,&v);
120         u=rd();
121         v=rd();
122         add(u,v);
123         add(v,u);
124     }
125     S=n,mx[rt=0]=2333333;
126     dfsrt(1,0);
127     divide(rt);
128     //for(int i=1;i<=m;i++)printf("%d ",anss[i]);
129     for(int i=1;i<=m;i++)sum+=anss[i];
130     if(n%3==1||n%3==2){
131         ans1=(double)((double)sum*(n/3)*(n/3+1))/(double)((double)n*(n-1));
132         if(n%3==1)printf("%.2lf\n",ans1);
133         else printf("%.2lf\n%.2lf\n",ans1,ans1);
134     }
135     ans2=(double)((double)sum*(n/3)*(n/3-1))/(double)((double)n*(n-1));
136     if(n%3==0)printf("%.2lf\n%.2lf\n%.2lf",ans2,ans2,ans2);
137     else if(n%3==1)printf("%.2lf\n%.2lf",ans2,ans2);
138     else printf("%.2lf",ans2);
139     return 0;
140 }

猜你喜欢

转载自www.cnblogs.com/dcdcbigbig/p/9762638.html