【gdgzezoi】Problem B: 简单的问题 Many Easy Problems

Description
有一天, Aoki给了Takahashi这样一个问题:

  • 给定一颗有N个节点的树和一个整数K. 这些节点从1到N标号, 边被表示为整数对(ai,bi).
  • 对于一个点集S, 我们定义f(S)表示一棵包含S中所有节点的最小子树的节点数量.(子树被定义为原树中的一个连通子图)
  • 我们有(nk)种在整棵树中选K个节点的方案. 对于所有这些方案, 我们用S表示选择的节点组成的集合, 请你求出所有(nk)个集合的f(S)之和. 答案对924844033(质数)取模.

Takahashi觉得这个问题太傻, 因此他决定求出对于K=1,2,⋯N的所有答案.
Input
第一行一个整数 n ,接下来 n−1 行,每行两个整数 ai,bi 。

Output
N行, 第i行表示当K=i时的答案模924844033得到的余数.
Sample Input
sample input 1:
3
1 2
2 3

sample input 2:
4
1 2
1 3
1 4

sample input 3:
7
1 2
2 3
2 4
4 5
4 6
6 7
Sample Output
sample output 1:
3
7
3

sample output 2:
4
15
13
4

sample output 3:
7
67
150
179
122
45
7
HINT

样例 1 当K=2时答案如上图 。

数据满足:

  • 2≤N≤2×105
  • 1≤ai,bi≤N
  • 给定的图是一颗树

大概有27分左右满足n≤2700。。?

思路

首先显然可以考虑每个点的贡献之后再容斥,就变成了对每个x求∑mk=1(ckx),其中m=2∗(n−1),ck是每条边两边的子树大小。

注意到ck≤n,所以把相同的ck合到一起之后,就变成了∑n k=1 ck(k/x)=1/x! ∑k ckk!/(k−x)!

发现是个卷积,直接NTT就行了。

代码

#include<bits/stdc++.h>
#define ll long long
#define N 800077
#define mod 924844033
#define G 5
#define unG 554906420
using namespace std;
int n;
struct edge{int v,nxt;}e[N<<1];
int hd[N],cnt;
inline void add(int u, int v){e[++cnt]=(edge){v,hd[u]}, hd[u]=cnt;}
int power(int x, int y)
{
    int ret=1;
    while(y)
    {
        if(y&1) ret=(ll)ret*x%mod;
        x=(ll)x*x%mod;
        y>>=1;
    }
    return ret;
}
int siz[N],num[N];
void dfs(int u, int fa){
    siz[u]=1;
    for(int i=hd[u]; i; i=e[i].nxt) if(e[i].v!=fa){
        dfs(e[i].v,u);
        siz[u]+=siz[e[i].v];
        --num[siz[e[i].v]], --num[n-siz[e[i].v]];
    }
}
int fac[N],unfac[N];
int a[N],b[N],c[N];
struct Poly
{
    int n,bit,r[N];
    void init(int x)
    {
        for(n=1, bit=0; n<=x; n<<=1, ++bit);
        for(int i=1; i<n; ++i) r[i] = (r[i>>1]>>1) | ((i&1)<<(bit-1));
    }
    void dft(int *a, int f)
    {
        for(int i=0; i<n; ++i) if(i<r[i]) swap(a[i],a[r[i]]);
        for(int i=1; i<n; i<<=1)
        {
            int wn = power(f==1 ? G : unG, (mod-1)/(i<<1));
            for(int j=0; j<n; j+=(i<<1)){
                int w=1, x, y;
                for(int k=0; k<i; ++k, w=(ll)w*wn%mod)
                    x=a[j+k], y=(ll)w*a[j+i+k]%mod,
                    a[j+k]=(x+y)%mod, a[j+i+k]=(x-y+mod)%mod;
            }
        }
        if(f==-1)
        {
            int tmp=power(n,mod-2);
            for(int i=0; i<n; ++i) a[i]=(ll)a[i]*tmp%mod;
        }
    }
}NTT;
int main()
{
    scanf("%d",&n);
    for(int i=1,u,v; i<n; ++i) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    fac[0]=1;
    for(int i=1; i<=n; ++i) fac[i]=(ll)fac[i-1]*i%mod;
    unfac[n]=power(fac[n],mod-2);
    for(int i=n-1; i>=0; --i) unfac[i]=(ll)unfac[i+1]*(i+1)%mod;
    dfs(1,0);
    num[n]=n;
    for(int i=0; i<=n; ++i)
        b[i]=((ll)num[n-i]*fac[n-i]%mod+mod)%mod,
        c[i]=unfac[i];
    NTT.init(n*2+1), NTT.dft(b,1), NTT.dft(c,1);
    for(int i=0; i<NTT.n; ++i) a[i]=(ll)b[i]*c[i]%mod;
    NTT.dft(a,-1);
    for(int i=1; i<=n; ++i) printf("%lld\n",(ll)a[n-i]*unfac[i]%mod);
}


发布了703 篇原创文章 · 获赞 392 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/100786759
今日推荐