• 题解[ABC207F Tree Patrolling]


    题目

    ABC207F

    Sol

    这道题非常的好。

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

    对于所有(kin[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
    ",(f[0][1][i]+f[1][1][i]+f[2][1][i])%P);
    	return 0;
    }
    

    完结撒花❀

  • 相关阅读:
    单例模式
    二、CSS
    十一、多线程
    十二、协程
    十、多进程
    九、内存管理
    八、元类
    七、上下文管理器/魔术方法
    六、单例模式
    五、装饰器
  • 原文地址:https://www.cnblogs.com/xxbbkk/p/15376847.html
Copyright © 2020-2023  润新知