潜入行动

题目大意

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

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

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

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

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

解题思路

dp[u][j][0/1][0/1]dp[u][j][0/1][0/1] 表示 uu 的字数内装 jj 个监听设备,uu 装了,其中 uu 点放没放装置,uu 点有没有被监听到的方案数(在以 uu 为根的子树中除 uu 外的其它结点都被监听到了)。

咕咕咕。。。

AC CODE

#include <bits/stdc++.h>
using namespace std;

namespace fastio
{
	int len = 0;
	char ibuf[(1 << 20) + 1], *iS, *iT, out[(1 << 23) + 1];
	int read()
	{
		int x = 0, t = 0;
		char c = getchar();
		while(c < '0' || c > '9')
		{
			t |= c == '-';
			c = getchar();
		}
		while(c >= '0' && c <= '9')
		{
			x = (x << 3) + (x << 1) + (c ^ 48);
			c = getchar();
		}
		return t ? -x : x;
	}
	char getcA()
	{
		char c = getchar();
		while(c < 'A' || c > 'Z') c = getchar();
		return c;
	}
	char getca()
	{
		char c = getchar();
		while(c < 'a' || c > 'z') c = getchar();
		return c;
	}
	void putc(char c)
	{
		out[len++] = c;
	}
	void write(int x)
	{
		if(x < 0) putc('-'), x = -x;
		if(x > 9) write(x / 10);
		putc(x % 10 + 48);
	}
	struct af
	{
		~af()
		{
			fwrite(out, 1, len, stdout);
			len = 0;
		}
	} Af;
}

using namespace fastio;

#define _ 100005

const long long mod = 1e9 + 7;

int n, k;

int siz[_];

int dp[_][105][2][2], tmp[105][2][2];

int tot, head[_], to[_ << 1], nxt[_ << 1];

void add(int u, int v)
{
	to[++tot] = v;
	nxt[tot] = head[u];
	head[u] = tot;
}

void dfs(int u, int fa)
{
	siz[u] = dp[u][0][0][0] = dp[u][1][1][0] = 1;
	for(int e = head[u]; e; e = nxt[e])
	{
		int v = to[e];
		if(v == fa) continue;
		dfs(v, u);
		memcpy(tmp, dp[u], sizeof tmp);
		memset(dp[u], 0, sizeof dp[u]);
		for(int i = 0; i <= min(siz[u], k); ++i)
		{
			for(int j = 0; i + j <= k && j <= min(siz[v], k - i); ++j)
			{
				dp[u][i + j][0][0] = (dp[u][i + j][0][0] + (long long)1ll * tmp[i][0][0] * dp[v][j][0][1]) % mod;

				dp[u][i + j][0][1] = (dp[u][i + j][0][1] + (long long)1ll * tmp[i][0][1] * (dp[v][j][0][1] + dp[v][j][1][1])) % mod;
				dp[u][i + j][0][1] = (dp[u][i + j][0][1] + (long long)1ll * tmp[i][0][0] * dp[v][j][1][1]) % mod;

				dp[u][i + j][1][0] = (dp[u][i + j][1][0] + (long long)1ll * tmp[i][1][0] * (dp[v][j][0][0] + dp[v][j][0][1])) % mod;

				dp[u][i + j][1][1] = (dp[u][i + j][1][1] + (long long)1ll * tmp[i][1][0] * (dp[v][j][1][0] + dp[v][j][1][1])) % mod;
				dp[u][i + j][1][1] = (dp[u][i + j][1][1] + (long long)1ll * tmp[i][1][1] * (1ll * dp[v][j][0][0] + dp[v][j][0][1] + 1ll * dp[v][j][1][0] + dp[v][j][1][1])) % mod;
			}
		}
		siz[u] += siz[v];
	}
}

signed main()
{
	n = read(), k = read();
	for(int i = 1; i < n; ++i)
	{
		int u = read(), v = read();
		add(u, v);
		add(v, u);
	}
	dfs(1, -1);
	cout << (dp[1][k][0][1] + dp[1][k][1][1]) % mod << endl;
	return 0;
}
posted @ 2021-10-04 19:16  蒟蒻orz  阅读(9)  评论(0编辑  收藏  举报  来源