题解[ABC207F Tree Patrolling]

题目

ABC207F

Sol

这道题非常的好。

题目大意:给你一棵\(n\)个点的树,在一个点设立守卫能够覆盖到所有与这个点相连的点,问所有的\(2^n\)种设立守卫的方案中,覆盖到\(k\)个点的方案有多少个。

对于所有\(k\in[1,n]\),求出答案。

Step1设状态

\(f[0][i][j]\)​为在\(i\)​节点的子树中有\(j\)​​个点被覆盖,且节点\(i\)​未设立守卫且被覆盖的方案数。

\(f[1][i][j]\)为在\(i\)节点的子树中有\(j\)个点被覆盖,且节点\(i\)设立守卫。

\(f[2][i][j]\)​为在\(i\)​节点的子树中有\(j\)​个点被覆盖,且节点\(i\)​​未设立守卫且覆盖的方案数。

Step2边界条件

\(f[0][i][0]=f[1][st][1]=1\)

放则有一个点,不放就没有点。

Step3考虑转移

这一部分不难,代码很好理解,多想一想就可以写出来。

有一点点繁琐。

//p:父亲节点子树内的被看守的点的个数
//q:儿子节点子树内的被看守的点的个数
(f[0][st][p+q]+=f[0][st][p]*f[0][ed][q]%P)%=P;
(f[0][st][p+q]+=f[0][st][p]*f[2][ed][q]%P)%=P;
(f[1][st][p+q]+=f[1][st][p]*f[1][ed][q]%P)%=P;
(f[1][st][p+q]+=f[1][st][p]*f[2][ed][q]%P)%=P;
(f[2][st][p+q]+=f[2][st][p]*f[1][ed][q]%P)%=P;
(f[2][st][p+q]+=f[2][st][p]*f[0][ed][q]%P)%=P;
(f[2][st][p+q]+=f[2][st][p]*f[2][ed][q]%P)%=P;
(f[2][st][p+q+1]+=f[0][st][p]*f[1][ed][q]%P)%=P;//新增节点st
(f[1][st][p+q+1]+=f[1][st][p]*f[0][ed][q]%P)%=P;//新增节点ed

Step4考虑优化

树形背包优化。

每次在更新完父节点的\(f\)之后在累加儿子节点的\(size\)

当然每次记得清空\(f[1][st][p]\),这个值是会不断重新变化的。

Code

#include<bits/stdc++.h>
#define N (3010)
#define ll long long
#define int long long
using namespace std;
const ll P=1000000007;
int n;
ll sz[N],f[4][N][N];
vector<int>e[N];
inline void dfs(int st,int fa){
	sz[st]=1,f[0][st][0]=f[1][st][1]=1;
	for(int i=0;i<(int)e[st].size();i++){
		int ed=e[st][i];
		if(ed==fa) continue;
		dfs(ed,st);
	}
	for(int i=0;i<(int)e[st].size();i++){
		int ed=e[st][i];
		if(ed==fa) continue;
		for(int p=sz[st];p>=0;p--){
			for(int q=sz[ed];q>=0;q--){
				if(!q){
					(f[1][st][p+q+1]+=f[1][st][p]*f[0][ed][q]%P)%=P;
					continue;
				}
				(f[0][st][p+q]+=f[0][st][p]*f[0][ed][q]%P)%=P;
				(f[0][st][p+q]+=f[0][st][p]*f[2][ed][q]%P)%=P;
				(f[1][st][p+q]+=f[1][st][p]*f[1][ed][q]%P)%=P;
				(f[1][st][p+q]+=f[1][st][p]*f[2][ed][q]%P)%=P;
				(f[2][st][p+q]+=f[2][st][p]*f[1][ed][q]%P)%=P;
				(f[2][st][p+q]+=f[2][st][p]*f[0][ed][q]%P)%=P;
				(f[2][st][p+q]+=f[2][st][p]*f[2][ed][q]%P)%=P;
				(f[2][st][p+q+1]+=f[0][st][p]*f[1][ed][q]%P)%=P;
				(f[1][st][p+q+1]+=f[1][st][p]*f[0][ed][q]%P)%=P;				
			}
			f[1][st][p]=0;
		}
		sz[st]+=sz[ed];
	}
	return;
}
signed main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v),e[v].push_back(u);
	}
	dfs(1,0);
	for(int i=0;i<=n;i++) printf("%lld\n",(f[0][1][i]+f[1][1][i]+f[2][1][i])%P);
	return 0;
}

完结撒花❀

posted @ 2021-10-07 19:56  xxbbkk  阅读(51)  评论(0编辑  收藏  举报