bzoj 4015: [FJOI2014]树的重心 dp

主子树dp 



#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 205;
const int maxm = 505;
const LL mod = 10007;
int tot,he[maxn],ne[maxm],ver[maxm];
void add( int x,int y ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
}
LL ad( LL x,LL y ){
    x+=y;
    return x%mod;
}
LL mul( LL x,LL y ){
    x *= y;
    return x%mod;
}
int sz[maxn],root[2],n,num;
void dfs1( int x,int f ){
    sz[x] = 1;
    bool flag = true;
    for( int cure=he[x];cure;cure = ne[cure]){
        int y = ver[cure];
        if( y == f ) continue;
        dfs1(y,x);
        if(sz[y]*2 > n)flag = false;
        sz[x] += sz[y];
    }
    if( 2*(n-sz[x]) > n )flag = false;
    if(flag) root[num++] = x;
}
LL dp1[maxn][maxn];
void dfs( int x,int f ){
    memset( dp1[x],0,sizeof(dp1[x]) );
    dp1[x][0] = dp1[x][1] = 1;
    for( int cure = he[x];cure;cure = ne[cure] ){
        int y = ver[cure];
        if( y == f ) continue;
        dfs(y,x);
        for( int i = n;i >= 2;i-- ){
            for( int j = 1;j <= i-1;j++ ){
                dp1[x][i] = ad(dp1[x][i],dp1[x][i-j]*dp1[y][j]%mod);
            }
        }
    }
}
LL dp2[maxn];
LL ans;
void solve1( int x ){
    for( int sz = 1;sz <= n;sz++ ){
        memset( dp2,0,sizeof(dp2) );   dp2[0] = 1;
        for( int cure = he[x];cure;cure = ne[cure] ){
            int y = ver[cure];
            for( int i = sz;i >= 1;i-- ) {
                int h = min( (sz-1)/2,i );
                for ( int j = 1;j <=h;j++ ) {
                    dp2[i] = ad(dp2[i],dp2[i-j]*dp1[y][j]%mod);
                }
            }
        }
        ans += dp2[sz-1];
        ans %= mod;
    }
}
void solve2( int x,int f,LL* val ){
    for( int sz = 1;sz <= n/2;sz ++ ){
        memset( dp2,0,sizeof(dp2) );
        dp2[0] = dp2[1]= 1;
        for( int cure = he[x];cure;cure=ne[cure] ){
            int y = ver[cure];
            if( y == f ) continue;
            for( int i = sz;i >= 2;i-- ){
                for( int j = 1;j <= i-1;j++ ){
                    dp2[i] = ad(dp2[i],dp2[i-j]*dp1[y][j]%mod);
                }
            }
        }
        val[sz] = dp2[sz];
    }
}
LL val1[maxn],val2[maxn];
void init(int n){
    tot = 1;
    memset( he,0,sizeof(int)*(n+1) );
    num = ans = 0;
}
int main(){
    int ca,T= 0 ;
    scanf("%d",&ca);
    while(ca--){
        scanf("%d",&n);
        init(n);
        for( int x,y,i = 1;i < n;i++ ){
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs1(1,0);
        if( num==1 ){
            dfs(root[0],0);
            solve1(root[0]);
        }else{
            dfs(root[0],0);
            solve2( root[0],root[1],val1 );
            solve2( root[1],root[0],val2 );
            for( int i = 1;i <= n/2;i++ ){
                ans += val1[i]*val2[i]%mod;
                ans %= mod;
            }
        }
        printf("Case %d: %lld\n",++T,ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值