问题描述

LG4516

LOJ2546


题解

好一个毒瘤题。

hkk:JSOI的签到题

\(opt[i][j][0/1][0/1]\)代表结点\(i\)的子树,放置\(j\)个,\(i\)放不放,\(i\)是否覆盖的方案数。

DP方程太长,无力打出(真·原因:我要睡觉!)。


\(\mathrm{Code}\)

#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-'){
        fh=-1;ch=getchar();
    }
    else fh=1;
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+ch-'0';
        ch=getchar();
    }
    x*=fh;
}

const int maxn=100003;
const int mod=1000000007;

int sum(long long x,long long y){
    x=x%mod,y=y%mod;
    return (int)((x+y)%mod);
}

int opt[maxn][103][2][2];
int tmp[103][2][2],size[maxn];

int n,k;

int Head[maxn],to[maxn*2],Next[maxn*2],tot;

void add(int x,int y){
    to[++tot]=y,Next[tot]=Head[x],Head[x]=tot;
}

void dp(int x,int fa){
    size[x]=opt[x][0][0][0]=opt[x][1][1][0]=1;
    for(int i=Head[x];i;i=Next[i]){
        int y=to[i];
        if(y==fa) continue;
        dp(y,x);
        for(int j=0;j<=min(size[x],k);j++){
            tmp[j][0][0]=opt[x][j][0][0],opt[x][j][0][0]=0;
            tmp[j][0][1]=opt[x][j][0][1],opt[x][j][0][1]=0;
            tmp[j][1][0]=opt[x][j][1][0],opt[x][j][1][0]=0;
            tmp[j][1][1]=opt[x][j][1][1],opt[x][j][1][1]=0;
        }
        for(int j=0;j<=min(size[x],k);j++){
            for(int p=0;p<=min(size[y],k-j);p++){
                opt[x][j+p][0][0]=sum((long long)opt[x][j+p][0][0],(long long)tmp[j][0][0]*(long long)opt[y][p][0][1]);
                opt[x][j+p][0][1]=sum((long long)opt[x][j+p][0][1],(long long)tmp[j][0][0]*(long long)opt[y][p][1][1]+(long long)tmp[j][0][1]*((long long)opt[y][p][1][1]+(long long)opt[y][p][0][1]));
                opt[x][j+p][1][0]=sum((long long)opt[x][j+p][1][0],(long long)tmp[j][1][0]*((long long)opt[y][p][0][0]+(long long)opt[y][p][0][1]));
                opt[x][j+p][1][1]=sum((long long)opt[x][j+p][1][1],(long long)tmp[j][1][0]*((long long)opt[y][p][1][0]+(long long)opt[y][p][1][1])+(long long)tmp[j][1][1]*((long long)opt[y][p][0][0]+(long long)opt[y][p][0][1]+(long long)opt[y][p][1][0]+(long long)opt[y][p][1][1]));
            }
        }
        size[x]+=size[y];
    }
}

int main(){
    read(n);read(k);
    for(int i=1,x,y;i<n;i++){
        read(x);read(y);
        add(x,y);add(y,x);
    }
    dp(1,0);
    printf("%d\n",(int)(opt[1][k][0][1]+opt[1][k][1][1])%mod);
    return 0;
}