AtCoder Grand Contest 005 F - Many Easy Problems

版权声明:菜鸡blog,随便转载 https://blog.csdn.net/qq_36808030/article/details/79957828

题意:

f(k)表示在树上任选k个点所组成的最小联通块大小的和。
求出所有f(k)

题解:

这种题一般都单独考虑每个点的贡献。
单点贡献显然就是Cnkyson[x]Csize[y]k
所以ans[k]=x=1nCnkyson[x]Csize[y]k
观察发现无论k取多少,cik的系数都是不变的,设为a[i]
ans[k]=ina[i]Cik
这个式子就可以卷积了。
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL p=924844033,yg=5;
LL n;
struct node{
    LL y,next;
}a[400010];LL len=0,last[200010];
LL f[200010],inv[200010],A[800010],B[800010],bin[800010];
void ins(LL x,LL y)
{
    a[++len].y=y;
    a[len].next=last[x];last[x]=len;
}
void pre()
{
    f[0]=f[1]=inv[0]=inv[1]=1;
    for(LL i=2;i<=200000;i++) f[i]=f[i-1]*i%p,inv[i]=(p-p/i)*inv[p%i]%p;
    for(LL i=2;i<=200000;i++) inv[i]=inv[i-1]*inv[i]%p;
}
LL pow(LL a,LL b)
{
    LL ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%p;
        a=a*a%p;b>>=1;
    }
    return ans;
}
LL size[200010];
void ntt(LL *a,LL n,LL op)
{
    for(LL i=0;i<n;i++) bin[i]=(bin[i>>1]>>1)|((i&1)*(n>>1));
    for(LL i=0;i<n;i++) if(i<bin[i]) swap(a[i],a[bin[i]]);
    for(LL i=1;i<n;i<<=1)
    {
        LL wn=pow(yg,op==1?(p-1)/(2*i):(p-1)-(p-1)/(2*i)),w,t;
        for(LL j=0;j<n;j+=i<<1)
        {
            w=1;
            for(LL k=0;k<i;k++)
            {
                t=a[i+j+k]*w%p;w=w*wn%p;
                a[i+j+k]=(a[j+k]-t+p)%p;a[j+k]=(a[j+k]+t)%p;
            }
        }
    }
    if(op==-1)
    {
        LL Inv=pow(n,p-2);
        for(LL i=0;i<n;i++) a[i]=a[i]*Inv%p;
    }
}
void dfs(LL x,LL fa)
{
    size[x]=1;A[n]++;
    for(LL i=last[x];i;i=a[i].next)
    {
        LL y=a[i].y;
        if(y==fa) continue;
        dfs(y,x);size[x]+=size[y];
        A[size[y]]--;
    }
    if(n-size[x]) A[n-size[x]]--;
}
int main()
{
    scanf("%lld",&n);
    for(LL i=1;i<n;i++)
    {
        LL x,y;scanf("%lld %lld",&x,&y);
        ins(x,y);ins(y,x);
    }
    pre();dfs(1,0);
    for(LL i=0;i<=n;i++) B[i]=inv[i],A[i]+=A[i]<0?p:0,A[i]=A[i]*f[i]%p;
    reverse(B,B+n+1);
    LL N=1;while(N<(n+1)<<1) N<<=1;
    ntt(A,N,1);ntt(B,N,1);
    for(LL i=0;i<N;i++) A[i]=A[i]*B[i]%p;
    ntt(A,N,-1);
    for(LL i=1;i<=n;i++) printf("%lld\n",inv[i]*A[n+i]%p);
}
阅读更多

没有更多推荐了,返回首页