「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!
致虚极,守静笃,万物并作,吾以观其复