[CODECHEF]PRIMEDST
Posted jefflyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CODECHEF]PRIMEDST相关的知识,希望对你有一定的参考价值。
题意:求在树上任选一条路径,长度为质数的概率
直接点分,不难,之所以写是因为想记一下关于时间复杂度的东西...
我们采用按顺序加子树的方式统计答案,记一个深度有多少个点,卷积统计答案
如果当前节点的子树最深深度分别为$d_{1cdots m}$,那么我们合并$i$时的数据规模为$max{d_{1cdots i-1}}+d_i$,如果直接做可以被卡到$n^2$
所以我们把$d_i$从小到大排序,这样做的总数据规模就是$sum d_i$级别的,也就是不超过当前子树大小,符合点分的要求
#include<stdio.h> #include<math.h> #include<string.h> #include<algorithm> using namespace std; typedef long long ll; typedef double du; const int T=50000,inf=2147483647; const du pi=3.141592653589793238462643383; int pr[T+10]; bool np[T+10]; void sieve(){ int i,j,M=0; np[1]=1; for(i=2;i<=T;i++){ if(!np[i])pr[++M]=i; for(j=1;j<=M&&i*pr[j]<=T;j++){ np[i*pr[j]]=1; if(i%pr[j]==0)break; } } } struct comp{ du x,y; comp(du a=0,du b=0){x=a;y=b;} }; comp operator+(comp a,comp b){return comp(a.x+b.x,a.y+b.y);} comp operator-(comp a,comp b){return comp(a.x-b.x,a.y-b.y);} comp operator*(comp a,comp b){return comp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} int rev[65536],N; comp w[16][65536]; void pre(int n){ int i,j,k; for(N=1,k=0;N<=n;N<<=1)k++; for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1)); for(i=2,k=0;i<=N;i<<=1,k++){ for(j=0;j<i>>1;j++)w[k][j]=comp(cos(j*pi/(i/2)),sin(j*pi/(i/2))); } } void fft(comp*a,int on){ int i,j,k,f; comp t; for(i=0;i<N;i++){ if(i<rev[i])swap(a[i],a[rev[i]]); } for(i=2,f=0;i<=N;i<<=1,f++){ for(j=0;j<N;j+=i){ for(k=0;k<i>>1;k++){ t=w[f][k]; t.y*=on; t=t*a[i/2+j+k]; a[i/2+j+k]=a[j+k]-t; a[j+k]=a[j+k]+t; } } } if(on==-1){ for(i=0;i<N;i++)a[i].x/=N; } } int h[50010],nex[100010],to[100010],M; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } bool v[50010]; int siz[50010]; void dfs1(int fa,int x){ siz[x]=1; for(int i=h[x];i;i=nex[i]){ if(!v[to[i]]&&to[i]!=fa){ dfs1(x,to[i]); siz[x]+=siz[to[i]]; } } } int mn,cn,n; void dfs2(int fa,int x){ int i,mx=0; for(i=h[x];i;i=nex[i]){ if(!v[to[i]]&&to[i]!=fa){ dfs2(x,to[i]); mx=max(mx,siz[to[i]]); } } mx=max(mx,n-siz[x]); if(mx<mn){ mn=mx; cn=x; } } int md[50010]; void dfs3(int fa,int x){ md[x]=1; for(int i=h[x];i;i=nex[i]){ if(!v[to[i]]&&to[i]!=fa){ dfs3(x,to[i]); md[x]=max(md[x],md[to[i]]+1); } } } int p[50010],d[50010],td[50010]; void dfs4(int fa,int x,int d){ td[d]++; for(int i=h[x];i;i=nex[i]){ if(!v[to[i]]&&to[i]!=fa)dfs4(x,to[i],d+1); } } bool cmp(int x,int y){return md[x]<md[y];} ll ans; comp A[65536],B[65536]; void solve(int x){ int i,j,M; dfs1(0,x); n=siz[x]; mn=inf; dfs2(0,x); x=cn; v[x]=1; dfs3(0,x); M=0; for(i=h[x];i;i=nex[i]){ if(!v[to[i]])p[++M]=to[i]; } if(M==0)return; sort(p+1,p+M+1,cmp); memset(d,0,(md[p[M]]+1)<<2); d[0]=1; for(i=1;i<=M;i++){ memset(td,0,(md[p[i]]+1)<<2); dfs4(x,p[i],1); pre(md[p[i-1]]+md[p[i]]); memset(A,0,N<<4); memset(B,0,N<<4); for(j=0;j<=md[p[i-1]];j++)A[j]=d[j]; for(j=0;j<=md[p[i]];j++)B[j]=td[j]; fft(A,1); fft(B,1); for(j=0;j<N;j++)A[j]=A[j]*B[j]; fft(A,-1); for(j=1;j<=md[p[i-1]]+md[p[i]];j++){ if(!np[j])ans+=llround(A[j].x); } for(j=0;j<=md[p[i]];j++)d[j]+=td[j]; } for(i=h[x];i;i=nex[i]){ if(!v[to[i]])solve(to[i]); } } int main(){ sieve(); int n,i,x,y; scanf("%d",&n); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } solve(1); printf("%.7lf",ans/(double)((ll)n*(n-1)/2)); }
CC昨晚不给提交,今早又复活了...
以上是关于[CODECHEF]PRIMEDST的主要内容,如果未能解决你的问题,请参考以下文章