题目链接

题意:

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

如果在节点 u 上安装监听设备,则 JYY 能够监听与 u 直接相邻所有的节点的通信。换言之,如果在节点 u 安装监听设备,则对于树中每一条边 (u,v) ,节点 v 都会被监听。

特别注意放置在节点 u 的监听设备并不监听 u 本身的通信,这是 JYY 特别为了防止外星人察觉部署的战术。

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

\(n\leq 100000 ,k\leq 100\)。


显然是树形背包DP。

但是,状态比较难设计。如果u没有被监视,则u的子节点必须至少有一个选。所以要加一维表示选不选。

而如果u被监视了,则u的子节点可以都不选。所以要加一维表示u是否被监视。

这样就好理解了。

f1[a+b][0]=(f1[a+b][0]+1ll*x0[a][0]*dp[v[i]][b][0][0])%md;
f1[a+b][1]=(f1[a+b][1]+1ll*x0[a][0]*dp[v[i]][b][0][1]+1ll*x0[a][1]*(dp[v[i]][b][0][0]+dp[v[i]][b][0][1]))%md;
f2[a+b][0]=(f2[a+b][0]+1ll*x1[a][0]*dp[v[i]][b][1][0])%md;
f2[a+b][1]=(f2[a+b][1]+1ll*x1[a][0]*dp[v[i]][b][1][1]+1ll*x1[a][1]*(dp[v[i]][b][1][1]+dp[v[i]][b][1][0]))%md;

关键是复杂度。

首先,常规树形背包是\(O(n^2)\)的。

就是每对点会在lca处贡献复杂度。

但是,这个算法,最初觉得是\(O(nk^2)\)的,实际上是\(O(nk)\)的。

证明:

  1. 根据正常树形背包的复杂度\(O(n^2)\),小于等于k的最多产生\(n/k*k^2\)的复杂度。
  2. 大于k与大于k的合并一次,被合并的就增加k,最多n/k次,最多产生\(n/k*k^2\)的复杂度。
  3. 大于k的与小于等于k的合并时,每个小于等于k的最多被合并一次,所以是\(n*s_1+n*s_2+...+n*s_m\),也是\(nk\)。

还有一种理解,不知道对不对:

把树按照dfs序变为序列。

然后,在子树中枚举取x个,可以理解为取dfs序的前(后)x个。

而合并时,认为一棵子树取后x个,另一棵取前y个。\((x+y\leq k)\)。这可以合并为长x+y的区间。

这其实就是长度不大于k的子串,最多有nk个。

但是,因为有取0个的情况,所以实际做题时,大约有2的常数。但那个常数就忽略了可以。

代码

#include <stdio.h>
#define min(a, b)(a < b ? a: b)
#define md 1000000007
inline int read() {
char ch;
while ((ch = getchar()) < '0' || ch > '9');
int rt = (ch ^ 48);
while ((ch = getchar()) >= '0' && ch <= '9') rt = (rt << 3) + (rt << 1) + (ch ^ 48);
return rt;
}
int dp[100002][102][2][2],f1[102][2],f2[102][2];
int x0[102][2],x1[102][2],sz[100002];
int fr[100002],ne[200002],v[200002],bs = 0,k;
void addb(int a, int b) {
v[bs] = b;
ne[bs] = fr[a];
fr[a] = bs++;
}
void dfs(int u, int fu) {
int si = 0;
for (int i = fr[u]; i != -1; i = ne[i]) {
if (v[i] != fu) {
dfs(v[i], u);
si += sz[v[i]];
}
}
for (int i = 0; i <= min(k, si); i++) x0[i][0] = x1[i][0] = 0;
x0[0][0] = x1[0][0] = 1;
si = 0;
for (int i = fr[u]; i != -1; i = ne[i]) {
if (v[i] == fu) continue;
int rt = sz[v[i]];
for (int a = 0; a <= min(si, k); a++) {
for (int b = 0; b <= min(rt, k - a); b++) {
f1[a + b][0] = (f1[a + b][0] + 1ll * x0[a][0] * dp[v[i]][b][0][0]) % md;
f1[a + b][1] = (f1[a + b][1] + 1ll * x0[a][0] * dp[v[i]][b][0][1] + 1ll * x0[a][1] * (dp[v[i]][b][0][0] + dp[v[i]][b][0][1])) % md;
f2[a + b][0] = (f2[a + b][0] + 1ll * x1[a][0] * dp[v[i]][b][1][0]) % md;
f2[a + b][1] = (f2[a + b][1] + 1ll * x1[a][0] * dp[v[i]][b][1][1] + 1ll * x1[a][1] * (dp[v[i]][b][1][1] + dp[v[i]][b][1][0])) % md;
}
}
si += rt;
for (int a = 0; a <= min(si, k); a++) {
x0[a][0] = f1[a][0];
x0[a][1] = f1[a][1];
x1[a][0] = f2[a][0];
x1[a][1] = f2[a][1];
f1[a][0] = f1[a][1] = f2[a][0] = f2[a][1] = 0;
}
}
for (int a = 0; a <= min(si, k); a++) {
dp[u][a][0][0] = x0[a][1];
dp[u][a][1][0] = (x0[a][0] + x0[a][1]) % md;
}
for (int a = 1; a <= min(si + 1, k); a++) {
dp[u][a][0][1] = x1[a - 1][1];
dp[u][a][1][1] = (x1[a - 1][0] + x1[a - 1][1]) % md;
}
sz[u] = si + 1;
}
int main() {
int n;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) fr[i] = -1;
for (int i = 0; i < n - 1; i++) {
int a,b;
a = read();
b = read();
addb(a, b);
addb(b, a);
}
dfs(1, 0);
printf("%d", (dp[1][k][0][0] + dp[1][k][0][1]) % md);
return 0;
}

[JSOI2018]潜入行动 (树形背包)的更多相关文章

  1. BZOJ5314: [Jsoi2018]潜入行动 (树形DP)

    题意:一棵树选择恰好k个结点放置监听器 每个监听器只能监听相邻的节点 问能使得所有节点被监听的种类数 题解:反正就是很well-known的树形DP了 至于时间复杂度为什么是nk 不会不学 很好想到四 ...

  2. [JSOI2018]潜入行动 树形DP_复杂计数

    code #include <cstdio> #include <algorithm> #include <cstring> #include <string ...

  3. BZOJ5314: [Jsoi2018]潜入行动

    BZOJ5314: [Jsoi2018]潜入行动 https://lydsy.com/JudgeOnline/problem.php?id=5314 分析: 裸树形背包,设\(f[x][i][0/1] ...

  4. poj2486Apple Tree[树形背包!!!]

    Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9989   Accepted: 3324 Descri ...

  5. cdoj 1136 邱老师玩游戏 树形背包

    邱老师玩游戏 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1136 Desc ...

  6. HDU 1011 树形背包(DP) Starship Troopers

    题目链接:  HDU 1011 树形背包(DP) Starship Troopers 题意:  地图中有一些房间, 每个房间有一定的bugs和得到brains的可能性值, 一个人带领m支军队从入口(房 ...

  7. poj 1155 TELE (树形背包dp)

    本文出自   http://blog.csdn.net/shuangde800 题目链接: poj-1155 题意 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构, ...

  8. bzoj 4813: [Cqoi2017]小Q的棋盘 [树形背包dp]

    4813: [Cqoi2017]小Q的棋盘 题意: 某poj弱化版?树形背包 据说还可以贪心... #include <iostream> #include <cstdio> ...

  9. 【BZOJ5314】[JSOI2018]潜入行动(动态规划)

    [BZOJ5314][JSOI2018]潜入行动(动态规划) 题面 BZOJ 洛谷 题解 不难想到一个沙雕\(dp\),设\(f[i][j][0/1][0/1]\)表示当前点\(i\),子树中一共放了 ...

随机推荐

  1. Word 查找替换高级玩法系列之 -- 把论文中的缩写词快速变成目录下边的注释表

    1. 前言 问题:Word写论文如何把文中的缩写快速转换成注释表? 原来样子: 想要的样子: 2. 步骤 使用查找替换高级用法,替换缩写顺序 选中所有文字 打开查找替换对话框,输入以下表达式: 替换后 ...

  2. SDOI2010_大陆争霸(邻接表存图)

    题目描述 在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯 ...

  3. 剑指offer58:对称的二叉树。判断一颗二叉树是不是对称的,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的

    1 题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 2 思路和方法 定义一种遍历算法,先遍历右子结点再遍历左子结点:如对称先序 ...

  4. python笔记005-字符串-列表-元组

    目录 1 上次作业补充拓展... 1 1.1 进制转换... 1 1.2 类型判断... 1 2 今日学习内容... 2 2.1 格式化输出... 2 2.2 基本运算符... 2 2.2.1 算术运 ...

  5. MySQL5.7主从从配置

    主从从,也称为级联主从,数据流向:A(主)->B(从)->C(从从),主从从级联复制. 应用场景 在主从配置的基础上,再增加一个从库,进一步提高数据安全,容灾备份. 读写分离,从库只用于查 ...

  6. C#委托和事件的使用示例

    一.委托 使用委托时要先实例化,和类一样,使用new关键字产生委托的新实例,然后将一个或者多个与委托签名匹配的方法与委托实例关联.随后调用委托时,就会调用所有与委托实例关联的方法. 与委托关联可以是任 ...

  7. IDEA如何本机调试springboot应用打的jar包

    背景: 我用命名行 执行 java -jar  ***.jar发现 springboot启动时抛出错误,因此想debug进去看看究竟为什么出错. 1  在命令行执行 java -jar -Xdebug ...

  8. .net core 依赖注入在特性中的应用

    .net core 依赖注入在特性中的应用,不知道怎么用属性注入,那么在特性中的构造函数里,怎么用接口的方法呢? 来一个简单的例子: 主要思路是把ServiceProvider 静态全局化: publ ...

  9. ASP.NET WEB应用程序(.network4.5)MVC 工作原理

    MVC就是模型.视图.控制器. 项目中控制器对应Controllers目录,视图对应Views目录,模型对应Models目录. 1.当我们创建一个控制器时,比如在Controllers目录新建一个名字 ...

  10. 开启HSTS让浏览器强制跳转HTTPS访问

    开启HSTS让浏览器强制跳转HTTPS访问 来源 https://www.cnblogs.com/luckcs/articles/6944535.html 在网站全站HTTPS后,如果用户手动敲入网站 ...