• AT2064 [AGC005F] Many Easy Problems 容斥+NTT


    题意:令 $f(i)$ 表示对于 $inom{n}{i}$ 种包含 $i$ 个点的最小连通块的总节点个数和.

    面对个数和/价值和且点和点之间没有限制条件的问题时可以考虑单独处理每个点的贡献.    

    考虑点 $j$ 对 $f(i)$ 的贡献.  

    那么 $j$ 对 $f(i)$ 有贡献时分两种情况.   

    1. $j$ 是 $i$ 个点中的一个.

    2. $j$ 不是 $i$ 个点中的一个,但是 $j$ 被这个连通块所包含,那么就意味着至少 $j$ 的两个儿子中有 $i$ 集合中的点.      

    对于情况 1,方案数为 $inom{n-1}{i-1}.$  

    对于情况 2,方案数为 $inom{n-1}{i}-sum_{v subseteq son[j] } inom{son[v]}{i}.$    

    两种情况总和为:$inom{n}{i}-sum_{v subseteq son[j] } inom{son[v]}{i}$ 

    那么对于所有点加和,得 $f(i)=n inom{n}{i}- sum_{j=i}^{n} inom{j}{i} num(j).$   

    $Rightarrow f(i)=n inom{n}{i} - i!sum_{j=i}^{n} frac{j!num(j)}{(j-i)!}.$  

    前面的是常数,但后后面的式子差是定值,所以将系数翻转做一遍 NTT 即可.    

    #include <cstdio>  
    #include <cstring> 
    #include <cmath> 
    #include <vector>  
    #include <algorithm>      
    #define ll long long   
    #define N 1000003 
    #define MAX 200005       
    #define mod 924844033
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;  
    int n,edges; 
    int hd[N],to[N],nex[N],bu[N],fac[N],inv[N],t[N],g[N],size[N],Ans[N];   
    void add(int u,int v) 
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;    
    }
    int qpow(int x,int y) 
    { 
        int tmp=1; 
        for(;y;y>>=1,x=(ll)x*x%mod) 
            if(y&1) tmp=(ll)tmp*x%mod; 
        return tmp;   
    }
    int INV(int x) { return qpow(x,mod-2); }      
    void NTT(int *a,int len,int flag) 
    {
        int i,j,k,mid;     
        for(i=k=0;i<len;++i) 
        {
            if(i>k) swap(a[i],a[k]); 
            for(j=len>>1;(k^=j)<j;j>>=1);    
        }
        for(mid=1;mid<len;mid<<=1) 
        {
            int wn=qpow(5,(mod-1)/(mid<<1));     
            if(flag==-1) wn=INV(wn);      
            for(i=0;i<len;i+=mid<<1) 
            { 
                int w=1;      
                for(j=0;j<mid;++j) 
                {
                    int x=a[i+j],y=(ll)w*a[i+j+mid]%mod;         
                    a[i+j]=(ll)(x+y)%mod;    
                    a[i+j+mid]=(ll)(x-y+mod)%mod;    
                    w=(ll)w*wn%mod;    
                }
            }
        }
        if(flag==-1) 
        {
            int in=INV(len); 
            for(i=0;i<len;++i) a[i]=(ll)a[i]*in%mod;    
        }
    } 
    int C(int x,int y) 
    {
        if(x<y||x<0||y<0) return 0;   
        return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;    
    }
    void init() 
    {
        int i,j;     
        fac[0]=inv[0]=1;     
        for(i=1;i<MAX;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=INV(fac[i]);       
    }
    void dfs(int u,int ff) 
    {
        size[u]=1; 
        for(int i=hd[u];i;i=nex[i]) 
        {
            int v=to[i]; 
            if(v==ff) continue;    
            dfs(v,u); 
            size[u]+=size[v];    
            bu[size[v]]++;   
        }  
        bu[n-size[u]]++;     
    }
    int main() 
    {     
        // setIO("input");   
        int i,j;    
        init();           
        scanf("%d",&n);   
        for(i=1;i<n;++i) 
        {
            int x,y;  
            scanf("%d%d",&x,&y),add(x,y),add(y,x);  
        }      
        dfs(1,0);  
        int ans=0;         
        for(i=0;i<=n;++i) g[i]=(ll)bu[i]*fac[i]%mod,t[n-i]=inv[i];          
        int lim=1;   
        while(lim<=2*n) lim<<=1;   
        NTT(g,lim,1),NTT(t,lim,1); 
        for(i=0;i<lim;++i) g[i]=(ll)g[i]*t[i]%mod;   
        NTT(g,lim,-1);      
        for(i=0;i<=n;++i)  Ans[i]=(ll)g[i+n]*inv[i]%mod;       
        for(i=1;i<=n;++i) 
        {
            int tmp=(ll)n*C(n,i)%mod;      
            printf("%d
    ",(ll)(tmp-Ans[i]+mod)%mod);   
        }        
        return 0;   
    }
    

      

  • 相关阅读:
    Android实战技巧之六:PreferenceActivity使用详解
    Gradle for Android 第三篇( 依赖管理 )
    From 虚拟机模板 创建单节点K8S1.14.1的操作步骤
    Android实例剖析笔记(二)
    Android实例剖析笔记(一)
    Android 传感器
    Eclipse:引用一个项目作为类库(图文教程)
    Android Studio导入Project的方法
    Android Studio导入GitHub上的项目常见问题(有例子)
    AndroidStudio导入项目常见问题
  • 原文地址:https://www.cnblogs.com/guangheli/p/12302623.html
Copyright © 2020-2023  润新知