[AGC005F]Many Easy Problems-FFT-容斥原理

来源:互联网 发布:淘宝的聚划算怎么抢 编辑:程序博客网 时间:2024/06/05 06:38

Many Easy Problems

Problem Statement

One day, Takahashi was given the following problem from Aoki:

You are given a tree with N vertices and an integer K. The vertices are numbered 1 through N. The edges are represented by pairs of integers (ai,bi).
For a set S of vertices in the tree, let f(S) be the minimum number of the vertices in a subtree of the given tree that contains all vertices in S.
There are ways to choose K vertices from the trees. For each of them, let S be the set of the chosen vertices, and find the sum of f(S) over all ways.
Since the answer may be extremely large, print it modulo 924844033(prime).
Since it was too easy for him, he decided to solve this problem for all K=1,2,…,N.

Constraints

2≦N≦200,000
1≦ai,bi≦N
The given graph is a tree.

Input

The input is given from Standard Input in the following format:

Na1 b1a2 b2:aN−1 bN−1

Output

Print N lines. The i-th line should contain the answer to the problem where K=i, modulo 924844033.

Sample Input 1

31 22 3

Sample Output 1

373

The diagram above illustrates the case where K=2. The chosen vertices are colored pink, and the subtrees with the minimum number of vertices are enclosed by red lines.

Sample Input 2

41 21 31 4

Sample Output 2

415134

Sample Input 3

71 22 32 44 54 66 7

Sample Output 3

767150179122457

想了很久很久然而只是想到了正解的很小一部分……
看了提示后推式子推了好久却就是差那么一点点没有完全推出来……
感觉自己好⑨啊


思路:
首先得想出个多项式时间内的暴力吧。

貌似直接考虑每个k时总体的答案有些不科学,那就单独考虑每个点的贡献。

可以发现,一个点被加入贡献,当且仅当把这个节点视为根节点后,所有选中的节点不在同一棵子树内。

[————–上面为提示因为本蒟蒻就想到这里—————-]

因为每个点贡献为1,所以可以发现答案为如下式子:

ansk=i=1n((nk)jchi(sizejk))

可以发现这个sizej很兹瓷合并同类项啊……
那么令pi=[sizej==i]
然后继续推新式子:

ansk=1k!(nn!(nk)!i=kn1pii!(ik)!)

pn=n,原先的pi=pi,变成:

ansk=1k!i=knpii!(ik)!
ans=k=1n(1k!i=knpii!(ik)!)

然后可以发现右边是个卷积……
做完了……

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;inline int read(){    int x=0;char ch=getchar();    while(ch<'0' || '9'<ch)ch=getchar();    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();    return x;}typedef long long ll;const int N=400009;const ll md=924844033;int n,m,l;int to[N<<1],nxt[N<<1],beg[N],tot;int rev[N<<1],siz[N];ll a[N<<1],b[N<<1],fac[N],inv[N];inline void chk(ll &a){if(a<0)a+=md;}inline ll qpow(ll a,ll b){    ll ret=1ll;    while(b)    {        if(b&1ll)            ret=ret*a%md;        a=a*a%md;        b>>=1;    }    return ret;}inline void add(int u,int v){    to[++tot]=v;    nxt[tot]=beg[u];    beg[u]=tot;}inline void dfs(int u,int fa){    a[n]++;siz[u]=1;    for(int i=beg[u];i;i=nxt[i])        if(to[i]!=fa)        {            dfs(to[i],u);            siz[u]+=siz[to[i]];            chk(--a[siz[to[i]]]);        }    chk(--a[n-siz[u]]);}inline void NTT(ll *a,int n,bool f){    for(int i=0;i<n;i++)        if(i<rev[i])            swap(a[i],a[rev[i]]);    for(int h=2;h<=n;h<<=1)    {        ll w=qpow(5,(md-1)/h);        if(f)w=qpow(w,md-2);        for(int j=0;j<n;j+=h)        {            ll wn=1;            for(int k=j;k<j+(h>>1);k++)            {                ll x=a[k],y=wn*a[k+(h>>1)]%md;                a[k]=(x+y)%md;                a[k+(h>>1)]=(x-y+md)%md;                wn=wn*w%md;            }        }    }    if(f)        for(ll i=0,invn=qpow(n,md-2);i<n;i++)            a[i]=a[i]*invn%md;}inline void init(){    fac[0]=1;    for(ll i=1;i<N;i++)        fac[i]=fac[i-1]*i%md;    inv[N-1]=qpow(fac[N-1],md-2);    for(ll i=N-1;i>=1;i--)        inv[i-1]=inv[i]*i%md;}int main(){    init();    n=read();    for(int i=1,u,v;i<n;i++)    {        u=read();v=read();        add(u,v);add(v,u);    }    dfs(1,1);    for(int i=1;i<=n;i++)        a[i]=a[i]*fac[i]%md;    for(int i=1;i<=n;i++)        b[i]=inv[n-i];    for(m=1,l=0;m<=(n<<1);m<<=1)l++;    for(int i=0;i<m;i++)        rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));    NTT(a,m,0);NTT(b,m,0);    for(int i=0;i<m;i++)        a[i]=a[i]*b[i]%md;    NTT(a,m,1);    for(int i=1;i<=n;i++)        printf("%lld\n",a[n+i]*inv[i]%md);    return 0;}