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);
    }
    
  • 相关阅读:
    【郑轻邀请赛 G】密室逃脱
    【郑轻邀请赛 C】DOBRI
    【郑轻邀请赛 F】 Tmk吃汤饭
    【郑轻邀请赛 I】这里是天堂!
    【郑轻邀请赛 B】base64解密
    【郑轻邀请赛 A】tmk射气球
    【郑轻邀请赛 H】 维克兹的进制转换
    解决adb command not found以及sdk环境配置
    adb shell 命令详解,android, adb logcat
    Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
  • 原文地址:https://www.cnblogs.com/youddjxd/p/11779666.html
Copyright © 2011-2022 走看看