• HDU5909 Tree Cutting(树形DP + FWT)


    题目

    Source

    http://acm.hdu.edu.cn/showproblem.php?pid=5909

    Description

    Byteasar has a tree T with n vertices conveniently labeled with 1,2,...,n. Each vertex of the tree has an integer value vi.

    The value of a non-empty tree T is equal to v1⊕v2⊕...⊕vn, where ⊕ denotes bitwise-xor.

    Now for every integer k from [0,m), please calculate the number of non-empty subtree of T which value are equal to k.

    A subtree of T is a subgraph of T that is also a tree.

    Input

    The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

    In each test case, the first line of the input contains two integers n(n≤1000) and m(1≤m≤210), denoting the size of the tree T and the upper-bound of v.

    The second line of the input contains n integers v1,v2,v3,...,vn(0≤vi<m), denoting the value of each node.

    Each of the following n−1 lines contains two integers ai,bi, denoting an edge between vertices ai and bi(1≤ai,bi≤n).

    It is guaranteed that m can be represent as 2k, where k is a non-negative integer.

    Output

    For each test case, print a line with m integers, the i-th number denotes the number of non-empty subtree of T which value are equal to i.

    The answer is huge, so please module 109+7.

    Sample Input

    2
    4 4
    2 0 1 3
    1 2
    1 3
    1 4
    4 4
    0 1 3 1
    1 2
    1 3
    1 4

    Sample Output

    3 3 2 3
    2 4 2 3

    分析

    题目大概说给一棵结点有权的树,定义一个连通块的价值为其所有结点点权异或和,问这棵树有几个价值为[0,m)的子图。

    • dp[u][m]表示以u结点为根的子树中,价值为m且包含u结点的子图的个数
    • 通过依次与各个儿子的状态值合并转移,合并利用FWT加速。。时间复杂度不明觉厉。。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define M 1000000007LL
    #define MAXN 1111
    
    struct Edge{
        int v,next;
    }edge[MAXN<<1];
    int NE,head[MAXN];
    void addEdge(int u,int v){
        edge[NE].v=v; edge[NE].next=head[u]; head[u]=NE++;
    }
    
    void FWT(long long *a,int n){
        for(int d=1; d<n; d<<=1){
            for(int m=d<<1,i=0; i<n; i+=m){
                for(int j=0; j<d; ++j){
                    long long x=a[i+j],y=a[i+j+d];
                    a[i+j]=(x+y)%M;
                    a[i+j+d]=(x-y+M)%M;
                }
            }
        }
    }
    void UFWT(long long *a,int n){
        for(int d=1; d<n; d<<=1){
            for(int m=d<<1,i=0; i<n; i+=m){
                for(int j=0; j<d; ++j){
                    long long x=a[i+j],y=a[i+j+d];
                    a[i+j]=(x+y)*500000004LL%M;
                    a[i+j+d]=(x-y+M)*500000004LL%M;
                }
            }
        }
    }
    void Convolution(long long *a,long long *b,int n){
        FWT(a,n); FWT(b,n);
        for(int i=0; i<n; ++i){
            a[i]=a[i]*b[i]%M;
        }
        UFWT(a,n);
    }
    
    int n,m;
    int val[MAXN];
    
    long long d[MAXN][1111];
    
    long long A[1111],B[1111];
    
    void dfs(int u,int fa){
        d[u][val[u]]=1;
        for(int i=head[u]; i!=-1; i=edge[i].next){
            int v=edge[i].v;
            if(v==fa) continue;
            dfs(v,u);
            memcpy(A,d[u],sizeof(A));
            memcpy(B,d[v],sizeof(B));
            Convolution(A,B,m);
            for(int i=0; i<m; ++i){
                d[u][i]+=A[i];
                d[u][i]%=M;
            }
        }
    }
    
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            for(int i=1; i<=n; ++i){
                scanf("%d",val+i);
            }
            NE=0;
            memset(head,-1,sizeof(head));
            int a,b;
            for(int i=1; i<n; ++i){
                scanf("%d%d",&a,&b);
                addEdge(a,b);
                addEdge(b,a);
            }
            memset(d,0,sizeof(d));
            dfs(1,1);
            for(int i=0; i<m; ++i){
                long long ans=0;
                for(int j=1; j<=n; ++j){
                    ans+=d[j][i];
                    ans%=M;
                }
                if(i) putchar(' ');
                printf("%I64d",ans);
            }
            putchar('
    ');
        }
        return 0;
    }
    
  • 相关阅读:
    显示图案
    圆的面积和周长
    Python基础--list列表删除元素
    Python基础--列表添加元素
    Python基础--列表创建访问删除
    Python基础--序列简介
    一个网页通用的测试用例(转载)
    测试计划与测试方案的区别
    判断一棵树是否是二叉平衡树
    判断丑数与寻找丑数
  • 原文地址:https://www.cnblogs.com/WABoss/p/6009268.html
Copyright © 2020-2023  润新知