zoukankan      html  css  js  c++  java
  • 51Nod1353 树

    题目看这里

    题意很简单,大概是有多少种删边方法使得每一块大小不小于k

    我们设一个树形dp,f[i][j]表示i的子树中,i所在联通块的大小为j的方案数有多少

    特别的,我们用f[i][0]表示∑f[i][j] (j>=k)

    那么可以写出以下转移:

    f[x][i+j]+=f[x][i]*f[v][j] (j>0)

    f[x][i]=f[x][i]*f[v][0]

    答案就是f[root][0]

    #include<vector>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define LL long long
    #define M 1000000007
    using namespace std;
    struct edge{ int v,nt; } G[4010];
    int h[2010],f[2010][2010],sz[2010],n,m,cnt=0;
    inline void ad(int& x,LL y){ x=(x+y)%M; }
    inline void adj(int x,int y){
        G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
        G[++cnt]=(edge){x,h[y]}; h[y]=cnt;
    }
    void dp(int x,int p){
        f[x][1]=sz[x]=1;
        for(int v,i=h[x];i;i=G[i].nt)
            if((v=G[i].v)!=p){
                dp(v,x);
                for(int i=sz[x];i;--i){
                    for(int j=sz[v];j;--j)
                        ad(f[x][i+j],(LL)f[x][i]*f[v][j]);
                    f[x][i]=(LL)f[x][i]*f[v][0]%M;
                }
                sz[x]+=sz[v];
            }
        for(int i=m;i<=sz[x];++i) ad(f[x][0],f[x][i]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int x,y,i=1;i<n;++i,adj(x,y)) scanf("%d%d",&x,&y);
        dp(1,0);
        printf("%d
    ",f[1][0]);
    }

  • 相关阅读:
    NYOJ 23 取石子(一)
    XYNUOJ 2026 素数环
    XYNUOJ 1756 魔法工会
    XYNUOJ 1784 胜利大逃亡
    NYOJ 18 The Triangle
    NYOJ 737 合并石子
    XYNUOJ 问题 B: 敌兵布阵
    NYOJ 1063 生活的烦恼
    XYNUOJ 1774 最少拦截系统
    XYNUOJ 1248 排队打水问题
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477089.html
Copyright © 2011-2022 走看看