zoukankan      html  css  js  c++  java
  • [bzoj2159]Crash 的文明世界——动态规划

    题目大意:

    给定一棵树,求每一个点的(s(i)=sum_{j=1}dis(i,j)^k)

    思路:

    题目所求(s(i)=sum_{j=1}dis(i,j)^k),考虑(k)次幂的组合意义,(x^k)表示(k)个不同的物品放入(x)个不同的箱子里面,即(x^k=sum_{i=1}^{x}{x choose i}{krace i} imes i!)

    对于每一个点(u),我们所求的就是:

    [egin{aligned} &sum_{i}sum_{j=1}^{k}{dis(u,i)choose j}{krace j} imes j!\ &=sum_{j=1}^{k}{krace j} imes j!sum_{i}{dis(u,i)choose j}\ end{aligned} ]

    (f_{u,j})表示点(u)的子树内组合数下标为(j)(sum_{i}{dis(u,i)choose j}),其中距离转移过来时需要强制+1,这可以利用组合数的简单递推公式来实现,不难得到状态转移方程:

    [f_{u,j}=f_{son,j}+f_{son,j-1} ]

    (g_{u,j})表示整个树上和(u)相关的节点的组合数和,同理可得状态转移方程:

    [g_{u,j}=f_{u,j}+g_{fa,j}-(f_{u,j}+f_{u,j-1})+g_{fa,j-1}-(f_{u,j-1}+f_{u,j-2}) ]

    然后就愉快的写完了。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.1.28
     * Problem : bzoj2159
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
        freopen("bzoj2159.in","r",stdin);
        freopen("bzoj2159.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T fl=1; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
    	for(;isdigit(ch);ch=getchar())_=(_<<1)+(_<<3)+(ch^'0');
    	_*=fl;
    }
    
    const int maxn=5e4+10;
    const int maxk=150+10;
    const int mod=10007;
    int n,k,f[maxn][maxk],g[maxn][maxk],ans[maxn];
    int beg[maxn],las[maxn<<1],to[maxn<<1],cnte=1;
    int fac[maxk],S[maxk][maxk];
    
    void add(int u,int v){
    	las[++cnte]=beg[u],beg[u]=cnte,to[cnte]=v;
    	las[++cnte]=beg[v],beg[v]=cnte,to[cnte]=u;
    }
    
    void math_init(){
    	fac[0]=1;
    	REP(i,1,k)fac[i]=fac[i-1]*i%mod;
    	S[0][0]=1;
    	REP(i,1,k)REP(j,1,i)
    		S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod;
    }
    
    void ad(int &_,int __){
    	_=(_+__)%mod;
    }
    
    void dfs1(int u,int fh){
    	for(int i=beg[u];i;i=las[i]){
    		int v=to[i];
    		if(v==fh)continue;
    		dfs1(v,u);
    		REP(j,0,k){
    			ad(f[u][j],f[v][j]);
    			if(j)ad(f[u][j],f[v][j-1]);
    		}
    	}
    	ad(f[u][0],1);
    }
    
    void dfs2(int u,int fh){
    	for(int i=beg[u];i;i=las[i]){
    		int v=to[i];
    		if(v==fh)continue;
    		REP(j,0,k){
    			ad(g[v][j],f[v][j]+g[u][j]-f[v][j]);
    			if(j>0)ad(g[v][j],-f[v][j-1]+g[u][j-1]-f[v][j-1]);
    			if(j>1)ad(g[v][j],-f[v][j-2]);
    		}
    		dfs2(v,u);
    	}
    }
    
    int main(){
        File();
    	read(n),read(k);
    	math_init();
    	int u,v;
    	REP(i,2,n){
    		read(u),read(v),add(u,v);
    	}
    	dfs1(1,0);
    	memcpy(g[1],f[1],sizeof(f[1]));
    	dfs2(1,0);
    	REP(i,1,n){
    		REP(j,1,k)
    			ad(ans[i],g[i][j]*fac[j]%mod*S[k][j]%mod);
    		ans[i]=(ans[i]+mod)%mod;
    	}
    	REP(i,1,n)printf("%d
    ",ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    值传递和引用传递(不是引用类型的传递)的区别
    字符串一旦定义,就表示开辟好了指定的空间,其内容就不可改变
    String类的直接赋值和构造方法赋值的区别
    字符串常量是String类的匿名对象
    Integer和int的区别(转)
    final的好处
    数组引用传递
    构造代码块
    ==和equals()的不同点
    Redis数据类型底层实现
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10330459.html
Copyright © 2011-2022 走看看