zoukankan      html  css  js  c++  java
  • 【JSOI2018】 潜入行动

    潜入行动

    题意

    外星人又双叒叕要攻打地球了,外星母舰已经向地球航行!这一次,JYY 已经联系好了黄金舰队,打算联合所有 JSOIer 抵御外星人的进攻。

    在黄金舰队就位之前,JYY 打算事先了解外星人的进攻计划。现在,携带了监听设备的特工已经秘密潜入了外星人的母舰,准备对外星人的通信实施监听。

    外星人的母舰可以看成是一棵 n 个节点、 n-1 条边的无向树,树上的节点用 、1,2,⋯,n 编号。JYY 的特工已经装备了隐形模块,可以在外星人母舰中不受限制地活动,可以神不知鬼不觉地在节点上安装监听设备。

    如果在节点 u 上安装监听设备,则 JYY 能够监听与 uu 直接相邻所有的节点的通信。换言之,如果在节点 u 安装监听设备,则对于树中每一条边 (u,v) ,节点 v 都会被监听。特别注意放置在节点 u 的监听设备并不监听 u 本身的通信,这是 JYY 特别为了防止外星人察觉部署的战术。

    JYY 的特工一共携带了 k 个监听设备,现在 JYY 想知道,有多少种不同的放置监听设备的方法,能够使得母舰上所有节点的通信都被监听?为了避免浪费,每个节点至多只能安装一个监听设备,且监听设备必须被用完。

    Solution

    首先树形DP,然后状态是(dp[u][s][0/1][0/1]),表示dp到了节点u、放了s个监听设备、自己放或不放、自己有没有被儿子节点监听的方案总数

    然后DP方程很容易搞出来,但是很冗长复杂。。。

    我们设在更新当前子树前的(dp[u]=g),那么有

    很容易明白的,相信我,别看题解,自己推一遍,对自己好

    [egin{cases} dp[u][j+l][0][0]+=g[j][0][0]*dp[v][l][0][1] \ dp[u][j+l][0][1]+=g[j][0][0]*dp[v][l][1][1]+g[j][0][1]*(dp[v][l][0][1]+dp[v][l][1][1]) \ dp[u][j+l][1][0]+=g[j][1][0]*(dp[v][l][0][0]+dp[v][l][0][1]) \ dp[u][j+l][1][1]+=g[j][1][0]*(dp[v][l][1][0]+dp[v][l][1][1])+g[j][1][1]*(dp[v][l][0][0]+dp[v][l][0][1]+dp[v][l][1][0]+dp[v][l][1][1]) \ end{cases} ]

    简单明了

    code:

    #include<bits/stdc++.h>
    using namespace std;
    struct qwq{
    	int v;
    	int nxt;
    }edge[200010];
    int head[200010];
    int cnt=-1;
    void add(int u,int v){
    	edge[++cnt].nxt=head[u];
    	edge[cnt].v=v;
    	head[u]=cnt;
    }
    const int mod=1e9+7;
    int dp[100010][110][2][2];
    int g[110][2][2];
    int siz[100010];
    int k;
    void dfs(int u,int fa) {
    	siz[u]=dp[u][0][0][0]=dp[u][1][1][0]=1;
    	for(int i=head[u];~i;i=edge[i].nxt){
    		int v=edge[i].v;
    		if(v==fa)continue;
    		dfs(v,u);
    		for(int j=0;j<=min(siz[u],k);j++){
    			g[j][0][0]=dp[u][j][0][0];
    			g[j][0][1]=dp[u][j][0][1];
    			g[j][1][0]=dp[u][j][1][0];
    			g[j][1][1]=dp[u][j][1][1];
    		}
    		memset(dp[u],0,sizeof(dp[u]));
    		for(int j=0;j<=min(siz[u],k);j++){
    			for(int l=0;l<=min(siz[v],k-j);l++){
    				dp[u][j+l][0][0]=(dp[u][j+l][0][0]+0ll
    				+1ll*g[j][0][0]*dp[v][l][0][1])%mod;
    				dp[u][j+l][0][1]=(dp[u][j+l][0][1]+0ll
    				+1ll*g[j][0][0]*dp[v][l][1][1]
    				+1ll*g[j][0][1]*(dp[v][l][0][1]+0ll+dp[v][l][1][1]))%mod;
    				dp[u][j+l][1][0]=(dp[u][j+l][1][0]+0ll
    				+1ll*g[j][1][0]*(dp[v][l][0][0]+0ll+dp[v][l][0][1]))%mod;
    				dp[u][j+l][1][1]=(dp[u][j+l][1][1]+0ll
    				+1ll*g[j][1][0]*(dp[v][l][1][0]+0ll+dp[v][l][1][1])
    				+1ll*g[j][1][1]*(0ll+dp[v][l][0][0]+dp[v][l][0][1]+dp[v][l][1][0]+dp[v][l][1][1]))%mod;
    			}
    		}
    		siz[u]+=siz[v];
    	}
    }
    signed main(){
    	memset(head,-1,sizeof(head));
    	int n;
    	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);
    	printf("%d
    ",(dp[1][k][0][1]+dp[1][k][1][1])%mod);
    }
    
  • 相关阅读:
    Visual Studio 进行单元测试时如何附加被测试文件的方法总结
    PowerDesigner实体模型CDM中关于建立Entity之间关系的备忘
    【转帖】C# 与 C++ 数据类型对照
    【转帖】解决继承窗体或用户控件时“visual继承当前被禁用,因为基类引用设备特定的组件或包含 p/invoke”问题
    【Winform窗体控件开发】之五 实现类型转换器TypeConverterAttribute
    SQL 使用CONVERT函数 格式化日期
    【转帖】const 与 readonly 的区别
    【转帖】C#与C Windows API数据类型对应关系
    【.Net Compact Framework开发】 使用 Visual Studio 对移动项目进行Unit Testing的方法总结
    【部署】Visual Studio 2008 打包部署.Net Framework 2.0 应用程序提示需要安装.Net Framework 3.5的解决方法
  • 原文地址:https://www.cnblogs.com/youddjxd/p/11779666.html
Copyright © 2011-2022 走看看