【題解】洛谷P4516(bzoj5314)[JSOI2018]潛入行動 樹形DP+計數類DP

題目鏈接
在這裏插入圖片描述
在這裏插入圖片描述


dp[u][iu][xu][yu]dp[u][iu][xu][yu] 表示在 uu 的子樹內選擇了 iuiu 個節點,其中節點 uu 有/無被安裝 (xu=0/1)(xu=0/1),節點 uu 有無被控制 (yu=0/1)(yu=0/1) 的方案數。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define _rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define _for(i,a,b) for(register int i=(a);i<(b);i++)
const int N=1e5+10,mod=1000000007;
typedef long long ll;
int n,k,tot,hd[N],sz[N],dp[N][110][2][2],pd[110][2][2],ans;
struct Edge{
	int v,nx;
}e[N<<1];
inline void sum(int&x,ll y)
{
	x=x+(y%mod);if(x>=mod)x-=mod;return;
}
void add(int u,int v)
{
	e[tot].v=v;
	e[tot].nx=hd[u];
	hd[u]=tot++;
}
void dfs(int u,int fa)
{
	sz[u]=1;dp[u][0][0][0]=1;dp[u][1][1][0]=1;
	for(int i=hd[u];~i;i=e[i].nx)
	{
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
		_rep(iu,0,min(sz[u],k))_for(xu,0,2)_for(yu,0,2)pd[iu][xu][yu]=dp[u][iu][xu][yu],dp[u][iu][xu][yu]=0;
		_rep(iu,0,min(sz[u],k))_rep(iv,0,min(sz[v],k-iu))
		{
			sum(dp[u][iu+iv][0][0],(ll)pd[iu][0][0]*dp[v][iv][0][1]);
            sum(dp[u][iu+iv][0][1],(ll)pd[iu][0][1]*(dp[v][iv][0][1]+dp[v][iv][1][1])+(ll)pd[iu][0][0]*dp[v][iv][1][1]);
            sum(dp[u][iu+iv][1][0],(ll)pd[iu][1][0]*(dp[v][iv][0][0]+dp[v][iv][0][1]));
            sum(dp[u][iu+iv][1][1],(ll)pd[iu][1][1]*((ll)dp[v][iv][0][0]+dp[v][iv][0][1]+dp[v][iv][1][0]+dp[v][iv][1][1])+(ll)pd[iu][1][0]*(dp[v][iv][1][0]+dp[v][iv][1][1]));
		}
		sz[u]+=sz[v];
	}
}
int main()
{
	//freopen("in.txt","r",stdin);
    memset(hd,-1,sizeof(hd));
	scanf("%d%d",&n,&k);
    int u,v;
    _for(i,1,n)scanf("%d%d",&u,&v),add(u,v),add(v,u);
    dfs(1,0);
    printf("%d\n",(dp[1][k][0][1]+dp[1][k][1][1])%mod);
    return 0;
}

總結

你谷講課黑題起手)此題是一個很好的樹形DP。要通過4個才能描述一個狀態,然後狀態轉移這些才能推出來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章