zoukankan      html  css  js  c++  java
  • 【HDU5909】Tree Cutting FWT

    令 $f[x][j]$ 表示以 $x$ 为根的子树,选出连通块的异或值为 $j$ 的方案数.

    然后有 $f[x][j]=f[x][j]+sum_{ioplus k=j} f[x][i] imes f[son][k]$.

    其中,$oplus$ 为异或符号.

    求解这个东西显然可以用 $FWT$ 来加速.

    有两种方式,第一个是当遍历 $x$ 的儿子的时候分别于每一个儿子都做一次 $FWT$,但是这个会比较慢.

    一个更好的方式是我们知道若干个多项式相乘不必一一相乘,而是统一进行 $FWT$,然后最后做一次 $IFWT$ 就行.

    但是这里有一个地方需要注意:$f[x][0]$ 必须要 +1,因为当 $x$ 的父亲与 $x$ 结合时有可能不选 $x$.     

    #include <cstdio> 
    #include <cstring> 
    #include <string>   
    #include <vector>  
    #include <cctype>   
    #include <algorithm>  
    #define N 1306  
    #define RG register
    #define ll long long 
    #define mod 1000000007 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;    
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }  
    int lim,inv,n;      
    int f[N][N],ans[N];    
    vector<int>G[N];   
    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; 
    }
    void FWT(int *a,int opt) 
    {
        int i,j,k;  
        for(i=1;i<lim;i<<=1) 
        {
            for(j=0;j<lim;j+=i<<1) 
            {
                for(k=0;k<i;++k) 
                {
                    int tmp=a[j+k];   
                    a[j+k]=(ll)(a[j+k]+a[j+k+i])%mod;       
                    a[j+k+i]=(ll)(tmp-a[j+k+i]+mod)%mod;     
                    if(opt==-1) 
                    {
                        a[j+k]=(ll)inv*a[j+k]%mod;   
                        a[j+k+i]=(ll)inv*a[j+k+i]%mod;   
                    }   
                }
            }
        }
    }
    void dfs(int u,int ff) 
    {
        FWT(f[u],1); 
        for(int i=0;i<G[u].size();++i) 
        {
            int y=G[u][i]; 
            if(y==ff) continue;   
            dfs(y,u);    
            for(int j=0;j<lim;++j) f[u][j]=(ll)f[u][j]*f[y][j]%mod;   
        }                   
        FWT(f[u],-1),f[u][0]=(f[u][0]+1)%mod,FWT(f[u],1);             
        G[u].clear();  
    }
    int main() 
    { 
        // setIO("input");  
        inv=qpow(2,mod-2);  
        int i,j,T;  
        T=read();  
        while(T--) 
        {  
            // scanf("%d%d",&n,&lim);     
            n=read(),lim=read(); 
            memset(f,0,sizeof(f)),memset(ans,0,sizeof(ans));   
            for(i=1;i<=n;++i) 
            {
                ++f[i][read()];   
            }
            for(i=1;i<n;++i) 
            {
                int x=read(),y=read();  
                G[x].push_back(y); 
                G[y].push_back(x);   
            }   
            dfs(1,0);  
            for(i=1;i<=n;++i)  FWT(f[i],-1);   
            for(i=1;i<=n;++i)  f[i][0]=(f[i][0]-1+mod)%mod;           
            for(i=1;i<=n;++i)  for(j=0;j<lim;++j) ans[j]=(ll)(ans[j]+f[i][j])%mod;   
            for(i=0;i<lim-1;++i) printf("%d ",ans[i]);   
            printf("%d
    ",ans[lim-1]);    
        }
        return 0; 
    }
    

      

  • 相关阅读:
    软工假期预习作业1
    2号团队-团队任务4:每日立会(汇总)
    2号团队-团队任务4:每日立会(2018-11-26)
    2号团队-团队任务4:每日立会(2018-11-27)
    第二小组首次会议记录
    第二次作业
    自我介绍+课后作业1:准备
    Linux安装redis
    Redis面试题
    Mybatis面试题
  • 原文地址:https://www.cnblogs.com/guangheli/p/12165440.html
Copyright © 2011-2022 走看看