• 【HDU5909】Tree Cutting(FWT)


    题目大意:
    给你一棵(n)个节点的树,每个节点都有一个小于(m)的权值
    定义一棵子树的权值为所有节点的异或和,问权值为(0..m−1)的所有子树的个数

    (f[i][j])表示节点(i)及其子树中异或和为(j)的方案数,发现合并答案的过程就是两个异或卷积,用(FWT)优化即可

    //minamoto
    #include<cstdio>
    #include<cstring>
    #define R register
    #define ll long long
    #define mem(a) memset(a,0,sizeof(a))
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=(1<<10)+5,P=1e9+7,inv=500000004;
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add_edge(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    int n,m,lim,x,u,v,f[N][N],ans[N];
    void FWT(int *A,int ty){
    	for(R int mid=1;mid<lim;mid<<=1)
    		for(R int j=0;j<lim;j+=(mid<<1))
    			for(R int k=0;k<mid;++k){
    				int x=A[j+k],y=A[j+k+mid];
    				A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
    				if(ty==-1)A[j+k]=mul(A[j+k],inv),A[j+k+mid]=mul(A[j+k+mid],inv);
    			}
    }
    void dfs(int u,int fa){
    	FWT(f[u],1);
    	go(u)if(v!=fa){
    		dfs(v,u);
    		fp(j,0,m-1)f[u][j]=mul(f[u][j],f[v][j]);
    	}FWT(f[u],-1),f[u][0]=add(f[u][0],1),FWT(f[u],1);
    }
    void solve(){
    	n=read(),m=read(),tot=0,mem(head),mem(f),mem(ans);
    	lim=1;while(lim<m)lim<<=1;
    	fp(i,1,n)x=read(),++f[i][x];
    	fp(i,1,n-1)u=read(),v=read(),add_edge(u,v),add_edge(v,u);
    	dfs(1,0);fp(i,1,n)FWT(f[i],-1);
    	fp(i,1,n)f[i][0]=dec(f[i][0],1);
    	fp(i,1,n)fp(j,0,m-1)ans[j]=add(ans[j],f[i][j]);
    	fp(i,0,m-1)printf("%d%c",ans[i]," 
    "[i==m-1]);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	int T=read();
    	while(T--)solve();
    	return 0;
    }
    
  • 相关阅读:
    【css】容器撑满浏览器--- height:100%
    【实践】js六道有趣的题
    【Canvas】树冠
    asp.net上传Excel文件到服务端进行读取
    HttpContext.Current多线程调用
    abstract修饰符,具体类与抽象类的区别
    如何快速恢复MyEclipse的默认主题
    日历源代码
    for语句应用:乘法表
    Java的优先级
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10195433.html
Copyright © 2020-2023  润新知