題解 AT2064 【[AGC005F] Many Easy Problems】
阿新 • • 發佈:2020-09-19
考慮每個點 \(x\) 對答案的貢獻,即總方案數減去不合法方案數,得:
\[\large\begin{aligned} f_i&=\sum_{x=1}^n\left(\binom{n}{i}-\sum_{\exists e(x,y)} \binom{size_y}{i}\right) \\ &=n\binom{n}{i}-\sum_{x=1}^n\sum_{\exists e(x,y)} \binom{size_y}{i} \\ \end{aligned} \]
設 \(cnt_i\) 為子樹大小為 \(i\) 的子樹個數,得:
\[\large\begin{aligned} f_i&=n\binom{n}{i}-\sum_{j=i}^n cnt_j\binom{j}{i} \\ &=n\binom{n}{i}-\sum_{j=i}^n cnt_j\frac{j!}{i!(j-i)!} \\ &=n\binom{n}{i}-\frac{1}{i!}\sum_{j=i}^n \frac{cnt_jj!}{(j-i)!} \\ &=n\binom{n}{i}-\frac{1}{i!}\sum_{j=0}^{n-i} \frac{cnt_{i+j}(i+j)!}{j!} \\ \end{aligned} \]
發現第二項是一個減法卷積的形式,用 \(NTT\) 即可求解。
#include<bits/stdc++.h> #define maxn 800010 #define P 924844033 #define G 5 using namespace std; typedef long long ll; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } ll n; ll rev[maxn],f[maxn],g[maxn],fac[maxn],ifac[maxn],siz[maxn],cnt[maxn]; struct edge { int to,nxt; }e[maxn]; int head[maxn],edge_cnt; void add(int from,int to) { e[++edge_cnt]={to,head[from]},head[from]=edge_cnt; } ll qp(ll x,ll y) { ll v=1; while(y) { if(y&1) v=v*x%P; x=x*x%P,y>>=1; } return v; } int calc(int n) { int lim=1; while(lim<=n) lim<<=1; for(int i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?lim>>1:0); return lim; } void NTT(ll *a,int lim,int type) { for(int i=0;i<lim;++i) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int len=1;len<lim;len<<=1) { ll wn=qp(G,(P-1)/(len<<1)); for(int i=0;i<lim;i+=len<<1) { ll w=1; for(int j=i;j<i+len;++j,w=w*wn%P) { ll x=a[j],y=w*a[j+len]%P; a[j]=(x+y)%P,a[j+len]=(x-y+P)%P; } } } if(type==1) return; ll inv=qp(lim,P-2); for(int i=0;i<lim;++i) a[i]=a[i]*inv%P; reverse(a+1,a+lim); } void mul(ll *f,ll *g) { int lim=calc(n<<1); NTT(f,lim,1),NTT(g,lim,1); for(int i=0;i<lim;++i) f[i]=f[i]*g[i]%P; NTT(f,lim,-1); } void dfs(int x,int fa) { siz[x]=1; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa) continue; dfs(y,x),siz[x]+=siz[y]; } cnt[siz[x]]++,cnt[n-siz[x]]++; } ll C(ll n,ll m) { return fac[n]*ifac[m]%P*ifac[n-m]%P; } void init() { fac[0]=ifac[0]=1; for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%P; ifac[n]=qp(fac[n],P-2); for(int i=n-1;i;--i) ifac[i]=ifac[i+1]*(i+1)%P; } int main() { read(n),init(); for(int i=1;i<n;++i) { int x,y; read(x),read(y); add(x,y),add(y,x); } dfs(1,0),g[0]=1; for(int i=1;i<=n;++i) f[i]=cnt[n-i]*fac[n-i]%P,g[i]=ifac[i]; mul(f,g),reverse(f,f+n+1); for(int i=1;i<=n;++i) printf("%lld\n",(n*C(n,i)%P-ifac[i]*f[i]%P+P)%P); return 0; }