zoukankan      html  css  js  c++  java
  • BZOJ4675 点对游戏

    传送门

    题目大意

    给定一棵$N$个点的树$(Nleq 5 imes 10^4)$,三个人轮流选点,每次等概率选一个之前没有被选过的点。

    定义$M$个距离(简单路径上的边数)的点对$(Mleq 10)$是幸运的,求每个人分别获得的幸运点对数量的期望。

     

    题解

    首先不难发现每个人选的点是独立的且数量是确定的

    假设选$k$个点,考虑每个点$x$对答案的贡献。设$P$表示$x$被选中的概率$=frac{k}{N}$

    枚举$x$作为点对中前一个点,对答案的贡献是$sum P imes (k-1)frac{V}{N-1}$,其中$V$表示能与$x$组成幸运点对的数量。

    化简之后得到$frac{k(k-1)}{N(N-1)}sum V$

    不难发现$sum V$其实就是树上所有的有序幸运点对数量,自然而然的想到点分治,不过由于这里的边权之和路径边数有关,所以我们可以使用长链剖分在$O(NM)$的时间复杂度内解决。

    假设无序幸运点对数量是$t$个,选出$k$个获得的幸运点对数量期望就是$frac{2tk(k-1)}{N(N-1)}$

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 100020
    using namespace std;
    int read(){
    	int nm=0,fh=1; int cw=getchar();
    	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    int n,m,fs[M],nt[M<<1],to[M<<1],tmp,D[12],t1,t2,t3;
    int mxd[M],dep[M],dfn[M],mxs[M],cnt,F[M],tot,sum;
    double m1,m2,m3,ans;
    void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
    void dfs1(int x,int last){
    	mxd[x]=0;
    	for(int i=fs[x];i!=-1;i=nt[i]){
    		if(to[i]==last) continue; dfs1(to[i],x);
    		if(mxd[to[i]]>=mxd[x]) mxd[x]=mxd[to[i]]+1,mxs[x]=to[i];
    	}
    }
    void dfs2(int x,int last){
    	dfn[x]=++cnt,F[dfn[x]]=1; if(mxs[x]) dfs2(mxs[x],x);
    	for(int i=1;i<=m;i++) if(D[i]<=mxd[x]) tot+=F[dfn[x]+D[i]];
    	for(int i=fs[x];i!=-1;i=nt[i]){
    		int v=to[i];
    		if(v==last||v==mxs[x]) continue; dfs2(v,x);
    		for(int k=0;k<=mxd[v];k++)
    			for(int j=1;j<=m;j++) if(D[j]>k&&D[j]-k-1<=mxd[x]) tot+=F[dfn[v]+k]*F[dfn[x]+D[j]-1-k];
    		for(int k=0;k<=mxd[v];k++) F[dfn[x]+k+1]+=F[dfn[v]+k];
    	}
    }
    int main(){
    	n=read(),m=read(),memset(fs,-1,sizeof(fs));
    	for(int i=1;i<=m;i++) D[i]=read();
    	for(int i=1;i<n;i++){int x=read(),y=read();link(x,y),link(y,x);}
    	t1=t2=t3=n/3,t1+=(n%3>0),t2+=(n%3>1);
    	m1=(t1*(t1-1)*1.0)/2.0,m2=(t2*(t2-1)*1.0)/2.0,m3=(t3*(t3-1)*1.0)/2.0;
    	dfs1(1,0),dfs2(1,0),ans=tot*2.0/((1.0*n)*(1.0*(n-1)));
    	printf("%.2f
    %.2f
    %.2f
    ",m1*ans,m2*ans,m3*ans);
    	return 0;
    }
    

      

  • 相关阅读:
    听说,好久不更了......
    JavaScript中数组常用方法
    html5常用英语单词
    重写与重载的区别
    RelativeLayout以及ListView
    树莓派基础配置
    通过yum安装lnmp-phpmyadmin
    POJ1850
    基于字典序的组合生成算法
    全排序之字典排序
  • 原文地址:https://www.cnblogs.com/OYJason/p/9760377.html
Copyright © 2011-2022 走看看