CF735E

题意:给一棵树,需要给树上的一些节点上色,要求任意节点在距离为k的范围以内至少有一个被染色的点,求方案数。

做法:显然的dp

树形DP。
  用f[i][j]表示i的子树中离i最近黑点的距离为j,且距离超过j的点都被满足的方案数。转移时新建一个临时数组tmp保存转移后的f[x]。设yx的子结点,枚举f[x][i]和f[y][j]

转移如下:
    1.若i+j2k,则此时min(i,j+1)k,对于长度为i+j+1的链上的所有点都可以找到一边距离k,因此状态合并以后是合法状态,转移tmp[min(i,j+1)]+=f[x][i]×f[y][j];
    2.若i+j>2k,则此时max(i,j+1)>k,链上肯定会存在一些点两边都够不到,转移tmp[max(i,j+1)]+=f[x][i]×f[y][j]

  每个点都要存当前不合法的状态,因为i子树外的点可以建立黑点,使得当前不合法的之后合法

  比如现在最远是k+x,如果i子树外某点p满足最远黑点为k-x,那么显然这个时候f[i][k+x]这个状态也合法了

  初始状态f[x][0]=1,表示不考虑子树内的情况,选择自己的方案数为1f[x][k+1]=1,表示自己本身不满足,但子结点都被满足的情况,主要是方便转移。
  答案为i<=kf[root][i]

代码:

#include<bits/stdc++.h>
#define N 2005
#define Mod 1000000007
using namespace std;
int dp[N][N],f[N],head[N],n,k,x,y,kk;
struct Tree{int nxt,to;}e[N];
inline void link(int x,int y){e[++kk].nxt=head[x];e[kk].to=y;head[x]=kk;}
void dfs(int u,int fa){
	dp[u][0]=dp[u][k+1]=1;
	for (int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if (v==fa) continue;
		dfs(v,u);
		memset(f,0,sizeof(f));
		for (int j=0;j<=2*k;j++){
			for (int p=0;p<=2*k;p++){
				if (j+p<=2*k){
					f[min(p+1,j)]+=(1ll*dp[u][j]*dp[v][p])%Mod;
					f[min(p+1,j)]%=Mod;
				}
				else {
					f[max(p+1,j)]+=(1ll*dp[u][j]*dp[v][p])%Mod;
					f[max(p+1,j)]%=Mod;
				}
			}
		}
		for (int j=0;j<=2*k;j++) dp[u][j]=f[j];
	}
}
int main(){
	scanf("%d%d",&n,&k);
	for (int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		link(x,y);link(y,x);
	}
	dfs(1,0);long long ans=0;
	for (int i=0;i<=k;i++) ans=1ll*(ans+dp[1][i])%Mod;
	printf("%lld\n",ans);
	return 0;
}

  

posted @ 2018-05-07 11:00  longint  阅读(134)  评论(0编辑  收藏  举报