[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的主要内容,如果未能解决你的问题,请参考以下文章

IDE 中的代码正确,但 CodeChef 中出现错误

Codechef 虫洞:我的逻辑有啥问题?

codechef问题COVIDLQ错误的应答错误

CodeChef GRAPHCNT

BZOJ4260: Codechef REBXOR

Codechef October Challenge 2018 游记