A - BZOJ5314 潜入行动
树形dp
dp[u][0-k][0/1][0/1]
第一维是节点编号
第二维是已使用的灯的数量
第三维表示当前节点是否有灯
第四维表示当前节点是否被点亮
处理子节点时相当于做了前缀和优化,tmp表示对于同一父节点当前子节点前所有其他子节点处理完后的结果。这样每个子节点处理的复杂度为
O
(
k
2
)
O(k^2)
O(k2)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int mod=1e9+7;
struct edge{
int v,next;
}e[maxn<<1];
int dp[maxn][110][2][2];
int cnt=0;
int head[maxn];
int sz[maxn];
int tmp[110][2][2];
void add(int u,int v){
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
int n,k;
void dfs(int u,int fa){
sz[u]=1;
dp[u][0][0][0]=dp[u][1][1][0]=1;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;if(v==fa)continue;
dfs(v,u);
for(int i=0;i<=sz[u]&&i<=k;i++){
for(int j=0;j<=1;j++){
for(int _=0;_<=1;_++){
tmp[i][j][_]=dp[u][i][j][_];
dp[u][i][j][_]=0;
}
}
}
for(int i=0;i<=sz[u]&&i<=k;i++){
for(int j=0;j<=sz[v]&&j<=k-i;j++){
dp[u][i+j][0][0]=((1ll*tmp[i][0][0]*dp[v][j][0][1])%mod+dp[u][i+j][0][0])%mod;
dp[u][i+j][1][0]=((1ll*tmp[i][1][0]*(dp[v][j][0][0]+dp[v][j][0][1])%mod)+dp[u][i+j][1][0])%mod;
dp[u][i+j][0][1]=((1ll*tmp[i][0][0]*dp[v][j][1][1]%mod+1ll*tmp[i][0][1]*(dp[v][j][0][1]+dp[v][j][1][1])%mod)%mod+dp[u][i+j][0][1])%mod;
dp[u][i+j][1][1]=((1ll*tmp[i][1][0]*(dp[v][j][1][1]+dp[v][j][1][0])%mod+1ll*tmp[i][1][1]*(1ll*(dp[v][j][0][0]+dp[v][j][0][1])+1ll*(dp[v][j][1][1]+dp[v][j][1][0])))+dp[u][i+j][1][1])%mod;
}
}
sz[u]+=sz[v];
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,-1);
cout<<(dp[1][k][1][1]+dp[1][k][0][1])%mod<<endl;
}