zoukankan      html  css  js  c++  java
  • Luogu4827 Crash的文明世界 组合、树形DP

    传送门


    又是喜闻乐见的(k)次幂求和题目

    那么(S(x) = sumlimits_{i=1}^n dist(i,x)^k = sumlimits_{i=1}^n sumlimits_{j=1}^k inom{dist(i,x)}{j} left{ egin{array}{cccc} k \ j end{array} ight} j! = sumlimits_{j=1}^k left{ egin{array}{cccc} k \ j end{array} ight} j! sumlimits_{i=1}^n inom{dist(i,x)}{j})

    因为组合数有优秀的性质:(inom{i+1}{j}=inom{i}{j} + inom{i}{j - 1}),可以用这一个式子做一个DP。

    (x)(x)的子树集合为(S_x)(dp_{i,j}=sumlimits_{x in S_i}inom{dist(i,x)}{j}),转移的时候考虑(i)的孩子(x)(dp_x)中的所有(dist)都会加上(1),也就是说(dp_{i,j} += sumlimits_{y in S_x} inom{dist(x,y)+1}{j} = sumlimits_{y in S_x} (inom{dist(x,y)}{j}+inom{dist(x,y)}{j-1}) = dp_{x,j}+dp_{x,j-1}),初始每一个节点(i)(dp_{i,0}=1),其余为(0)

    接下来设(up_{i,j} = sumlimits_{x otin S_i}inom{dist(i,x)}{j}),转移从一个点(i)转移到它的孩子(x),将(dp_x)(dp_i)的贡献消除之后得到(dp'_i),那么不难得到(up_{x,j} = up_{i,j}+up_{i,j-1}+dp'_{i,j}+dp'_{i,j-1})

    最后(sumlimits_{i=1}^n inom{dist(i,x)}{j} = dp_{x,j} + up_{x,j})

    #include<bits/stdc++.h>
    //this code is written by Itst
    using namespace std;
    
    int read(){
        int a = 0; char c = getchar();
        while(!isdigit(c)) c = getchar();
        while(isdigit(c)){
            a = a * 10 + c - 48;
            c = getchar();
        }
        return a;
    }
    
    const int _ = 50003 , MOD = 10007;
    struct Edge{
        int end , upEd;
    }Ed[_ << 1];
    int dp[_][157] , up[_][157] , tmp[157] , S[157][157] , ans[_];
    int N , K , head[_] , cntEd;
    
    void addEd(int a , int b){
        Ed[++cntEd] = (Edge){b , head[a]};
        head[a] = cntEd;
    }
    
    void dfs1(int x , int p){//dp
        dp[x][0] = 1;
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(Ed[i].end != p){
                dfs1(Ed[i].end , x);
                for(int j = K ; j ; --j)
                    dp[x][j] = (dp[x][j] + dp[Ed[i].end][j] + dp[Ed[i].end][j - 1]) % MOD;
                dp[x][0] = (dp[x][0] + dp[Ed[i].end][0]) % MOD;
            }
    }
    
    void dfs2(int x , int p){//up
        for(int i = 0 ; i <= K ; ++i)
            tmp[i] = (up[x][i] + dp[x][i]) % MOD;
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(Ed[i].end != p){
                up[Ed[i].end][0] = (tmp[0] + MOD - dp[Ed[i].end][0]) % MOD;
                for(int j = 1 ; j <= K ; ++j)
                    up[Ed[i].end][j] = (tmp[j] + 2 * MOD - (dp[Ed[i].end][j] + dp[Ed[i].end][j - 1])) % MOD;
                for(int j = K ; j ; --j)
                    up[Ed[i].end][j] = (up[Ed[i].end][j] + up[Ed[i].end][j - 1]) % MOD;
            }
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(Ed[i].end != p)
                dfs2(Ed[i].end , x);
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in","r",stdin);
        //freopen("out","w",stdout);
    #endif
        N = read(); K = read();
        for(int i = 1 ; i < N ; ++i){
            int a = read() , b = read();
            addEd(a , b); addEd(b , a);
        }
        S[1][1] = 1;
        for(int i = 2 ; i <= K ; ++i)
            for(int j = 1 ; j <= i ; ++j)
                S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * j) % MOD;
        dfs1(1 , 0); dfs2(1 , 0);
        int fac = 1;
        for(int j = 1 ; j <= K ; ++j){
            fac = 1ll * fac * j % MOD;
            for(int i = 1 ; i <= N ; ++i)
                ans[i] = (ans[i] + 1ll * (dp[i][j] + up[i][j]) * fac * S[K][j]) % MOD;
        }
        for(int i = 1 ; i <= N ; ++i)
            printf("%d
    " , ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    MySQL性能调优语句
    APP测试
    JForum项目搭建
    Bug的等级及定位
    mysql any和all的用法
    mysql产生随机数
    MySQL存储过程例子
    【转】 卡特兰数
    牛客小白月赛5 I 区间 (interval) 【前缀和】
    牛客小白月赛5 D 阶乘(factorial) 【前缀】
  • 原文地址:https://www.cnblogs.com/Itst/p/10843602.html
Copyright © 2011-2022 走看看