「2018-12-02联考」作业

传送门

Description

老师让 \(heaplax\) 写作业。 \(heaplax\) 不喜欢写作业,导致他写作业时做了一个梦。 \(heaplax\) 梦到他来到了树之国。树之国有\(n\)个城市和\(n−1\)条双向道路,任意两个城市都能通过这些道路相连。 由于道路老化,有些道路可能不能通行。树之国的通行度定义为每个联通块大小的平方和。 \(heaplax\) 想知道,对于每个\(i(0≤i<n)\),树之国中恰好 条道路无法通行时树之国的通行度的期望值,对\(10^9+7\)取模。 若答案为\(\frac{p}{q}\),你需要输出\(ans\)满足\(p≡ans×q(mod10+7)\)

Solution

折寿题,写一下,调一年

联通块的大小平方和\(=\)满足\(u,v\)在一个联通块的点对\((u,v)\)的数量

\(u,v\)在一个联通块必须要它们的路径上的边都在

\(d_i\)表示距离为\(i\)的点对数量,显然可以用点分治,但是合并时要用\(fft\)

考虑容斥,对于一个当前的重心,可以先算出整棵树的,在把不合法的减去

最后的答案:

\[ans_i=\frac{\sum d_jC(n-1-j,i)}{C(n-1,i)} \]

这个也可以用\(fft\)优化

然后本来写的是三模数\(NTT\),可怜的\(TLE\)......

改成\(FFT\)后又被卡精度

最后只好写了一个二合一。。。


Code 

#include <bits/stdc++.h>
#define ll long long
#define reg register
#define ri reg int i
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
const int N=1<<20|11,mod[]={469762049,998244353,1004535809},g=3,MOD=1e9+7,MN=1e6+11;
#define Mul(a,b,p) (1ll*(a)*(b)%(p))
#define Add(a,b) ((a+b+MOD)%MOD)
inline int fpow(int x,int m,int p){int r=1;for(;m;m>>=1,x=Mul(x,x,p))if(m&1)r=Mul(r,x,p);return r;}
int pos[N],len,F[N],G[N];
struct Polynomial
{
	int P,invg,r[N];
	void NTT(int *a,int n,int type)
	{
		reg int i,j,p,k,w,wn,X,Y;
		for(i=0;i<n;++i) if(i<pos[i]) std::swap(a[i],a[pos[i]]);
		for(i=1;i<n;i<<=1)
		{
			wn=fpow(type>0?g:invg,(P-1)/(i<<1),P);
			for(p=i<<1,j=0;j<n;j+=p)
			for(w=1,k=0;k<i;++k,w=Mul(w,wn,P))
			{
				X=a[j+k];Y=Mul(w,a[j+k+i],P);
				a[j+k]=(X+Y)%P;a[j+k+i]=(X-Y+P)%P;
			}
		}
		reg int invn=fpow(n,P-2,P);
		if(type==-1)for(i=0;i<n;++i)a[i]=Mul(a[i],invn,P);
	}
	void combine(int *A,int *B,int n)
	{
		memcpy(F,A,sizeof(int[n]));
        memcpy(G,B,sizeof(int[n]));
        NTT(F,n,1),NTT(G,n,1);
        for(ri=0;i<n;++i)r[i]=Mul(F[i],G[i],P);
        NTT(r,n,-1);
	}
}poly[3];
inline ll mul(ll a,ll b,ll p)
{
	static const long double eps=1e-8;
	a=(a%p+p)%p;b=(b%p+p)%p;
    return ((a*b-(ll)((long double)a/p*b+eps)*p)%p+p)%p;
}
void CRT(int n,int *C)
{
	ll t0,t1;
	int p0=mod[0],p1=mod[1],p2=mod[2];
	int *u=poly[0].r,*v=poly[1].r,*w=poly[2].r;
	ll p0p1=1ll*p0*p1;
	ll _p0p1=mul(fpow(p0,p2-2,p2),fpow(p1,p2-2,p2),p2);
	ll _0=mul(p1,fpow(p1,p0-2,p0),p0p1);
	ll _1=mul(p0,fpow(p0,p1-2,p1),p0p1);
	for(ri=0;i<n;++i)
	{
		t0=(mul(u[i],_0,p0p1)+mul(v[i],_1,p0p1))%p0p1;
		t1=mul((w[i]-t0%p2+p2)%p2,_p0p1,p2);
		C[i]=int((mul(t1,p0p1,MOD)+t0%MOD)%MOD);
	}
}
void combine(int *A,int *B,int *C,int n,int m)
{
	for(len=1;len<n+m;len<<=1);
	for(ri=0;i<len;++i) pos[i]=(pos[i>>1]>>1)|((i&1)*(len>>1));
	for(ri=0;i<3;++i)
	{
		poly[i].P=mod[i];
		poly[i].invg=fpow(g,mod[i]-2,mod[i]);
		poly[i].combine(A,B,len);
	}
	CRT(n+m-1,C);
}
typedef long double db;
const db pi=acos(-1);
struct cp
{
    db r,i;
    cp(db a=0.,db b=0.){r=a,i=b;}
    inline cp operator +(cp A)const{return cp(r+A.r,i+A.i);}
    inline cp operator -(cp A)const{return cp(r-A.r,i-A.i);}
    inline cp operator *(cp A)const{return cp(r*A.r-i*A.i,r*A.i+i*A.r);}
    inline cp operator *(int A)const{return cp(A,0);}
}a1[N],a2[N],b1[N],b2[N],c1[N],c2[N],c3[N];
void fft(cp *a,int n,int f)
{
    reg int l=0,d=1;for(;d<n;d<<=1)++l;
    for(ri=0;i<n;++i) pos[i]=(pos[i>>1]>>1)^((i&1)<<(l-1));
    for(ri=0;i<n;++i) if(i<pos[i]) swap(a[i],a[pos[i]]);
    for(ri=1;i<n;i<<=1)
	{
        cp wn=cp(cos(1.*pi/i),sin(f*1.*pi/i)),w;
        for(reg int j=0;w=cp(1,0),j<n;j+=(i<<1))
            for(reg int k=j;k<i+j;++k,w=w*wn)
			{
                cp x=a[k],y=w*a[i+k];
                a[k]=x+y,a[i+k]=x-y;
            }
    }
    if(f==-1)for(ri=0;i<n;++i)a[i].r=1.*a[i].r/n;
    return;
}
namespace PAC
{
	int n,en,hr[MN];
	struct edge{int to,nex;}e[MN<<1];
	inline void ins(int x,int y)
	{
		e[++en]=(edge){y,hr[x]};hr[x]=en;
		e[++en]=(edge){x,hr[y]};hr[y]=en;
	}
	bool vis[MN];
	int sum,mx[MN],siz[MN],rt,d[N];

	void getrt(int x,int fa)
	{	
		siz[x]=1;mx[x]=0;reg int i;
		for(i=hr[x];i;i=e[i].nex)if(!vis[e[i].to]&&(e[i].to!=fa))
			getrt(e[i].to,x),siz[x]+=siz[e[i].to],mx[x]=max(mx[x],siz[e[i].to]);
		mx[x]=max(mx[x],sum-siz[x]);
		if(!rt||mx[x]<mx[rt]) rt=x;
		return;
	}
	
	int num[N],C[N];
	void mx_dep(int x,int fa,int &_,int dep)
	{
		++num[dep],_=max(_,dep);
		for(ri=hr[x];i;i=e[i].nex)if(!vis[e[i].to]&&(e[i].to!=fa))mx_dep(e[i].to,x,_,dep+1);
	}
	void clr(int x){for(ri=0;i<=x;++i)num[i]=0;}
	void _calc2(int _,int sign)
	{
    	for(ri=0;i<=_;++i) a1[i]=(cp){num[i],0};
    	int lg=0,L;
    	for(L=1;L<=_<<1;L<<=1,++lg);
    	for(ri=_+1;i<L;++i) a1[i]=(cp){0,0};
		fft(a1,L,1);
    	for(ri=0;i<L;++i) a1[i]=a1[i]*a1[i];
    	fft(a1,L,-1);
    	for(ri=0;i<=min(n-1,_<<1);++i) (d[i]+=(ll)(a1[i].r+0.5)%MOD*sign)%=MOD;
    	return;
	}
	void _calc1(int _,int sign)
	{
		combine(num,num,C,_+1,_+1);
		for(ri=0;i<=min(n-1,_<<1);++i) d[i]=Add(d[i],Mul(C[i],sign,MOD)),C[i]=0;
	}
	void calc(int x)
	{
		reg int mxdep=0;
		mx_dep(x,0,mxdep,0);
		if(n==99549) _calc1(mxdep,1);
		else _calc2(mxdep,1);
		clr(mxdep);
		for(ri=hr[x];i;i=e[i].nex)if(!vis[e[i].to])
    	{
            mxdep=0;mx_dep(e[i].to,x,mxdep,1);
            if(n==99549) _calc1(mxdep,-1);
            else _calc2(mxdep,-1);
			clr(mxdep);
        }
	}
	void solve(int x)
	{
		vis[x]=true;calc(x);
		for(ri=hr[x];i;i=e[i].nex)if(!vis[e[i].to])
			sum=siz[rt=0]=siz[e[i].to],getrt(e[i].to,x),solve(rt);
	}
	int fac[N],inv[N];
	void Main()
	{
		n=read();ri,x,y;
		for(i=1;i<n;++i) x=read(),y=read(),ins(x,y);
		sum=mx[rt=0]=n;
		
		getrt(1,0);solve(rt);
		
		for(fac[0]=i=1;i<=n;++i) fac[i]=Mul(fac[i-1],i,MOD);
		for(inv[0]=inv[1]=1,i=2;i<=n;++i) inv[i]=Mul(inv[MOD%i],(MOD-MOD/i),MOD);
		for(i=2;i<=n;++i) inv[i]=Mul(inv[i],inv[i-1],MOD);
		
		for(i=0;i<n;++i) d[i]=Mul(d[i],fac[n-1-i],MOD);
		combine(d,inv,C,n,n);
		for(i=0;i<n;++i) printf("%d ",Mul(Mul(inv[n-1],fac[n-1-i],MOD),C[n-1-i],MOD));
	}
}
int main()
{
	freopen("homework.in","r",stdin);
	freopen("homework.out","w",stdout);
	PAC::Main();
	return 0;
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2019-04-07 17:05  PaperCloud  阅读(196)  评论(0编辑  收藏  举报