题目链接

题目

题目描述

“你,你认错人了。我真的,真的不是食人魔。”--蓝魔法师

给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于k,两种方案不同当且仅当存在一条边在一个方案中被删除,而在另一个方案中未被删除,答案对998244353取模

输入描述

第一行两个整数n,k, 表示点数和限制

2 <= n <= 2000, 1 <= k <= 2000

接下来n-1行,每行包括两个整数u,v,表示u,v两点之间有一条无向边

保证初始图联通且合法

输出描述

共一行,一个整数表示方案数对998244353取模的结果

示例1

输入

5 2
1 2
1 3
2 4
2 5

输出

7

题解

知识点:树形dp,背包dp,计数dp。

显然是个树上背包,但涉及组合计数。

设 \(dp[u][i]\) 表示以 \(u\) 为根的子树划分成大小不大于 \(k\) 连通块,且 \(u\) 所在连通块大小为 \(i\) 的方案数。这道题要剪枝,转移方程我用了刷表法。下面代码有打表和刷表的对比,明显刷表法更容易写出最佳的循环边界。转移方程为:

\[\left \{
\begin{array}{l}
dp[u][i+j] &= dp[u][i + j] + dp[u][i] \cdot dp[v][j]\\
dp[u][i] &= dp[u][i] + \sum dp[v][j]
\end{array}
\right .
\]
  1. 连接 \((u,v)\) , \(dp[u][i]\) 与 \(dp[v][j]\) 用乘法原理合并,最后得到 \(dp[u][i+j]\) ,显然 \(i+j\) 要小于等于 \(k\) 。 $i \in [1,\min(sz[u],k)] $ , \(j \in [1,\min (sz[v],k)]\) ,两者都要倒序遍历保证 \(i+j\) 是倒序的。
  2. 断开 \((u,v)\) , \(dp[u][i]\) 的方案加上 \(dp[v][j]\) 的所有方案数。为了防止 \(dp[u][i]\) 的更新影响 \(i+j\) ,因此这个更新要在一次 \(i\) 的更新最后执行。

时间复杂度 \(O(nk^2)\)

空间复杂度 \(O(nk)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int mod = 998244353;
int n, k;
vector<int> g[2007];
int dp[2007][2007], sz[2007]; /* void dfs(int u, int fa) {
dp[u][1] = 1;
sz[u] = 1;
for (auto v : g[u]) {
if (v == fa) continue;
dfs(v, u);
sz[u] += sz[v];
int sumv = 0;
for (int i = 1;i <= sz[v];i++) sumv = (sumv + dp[v][i]) % mod;
for (int i = min(sz[u], k);i >= 1;i--) {
dp[u][i] = 1LL * dp[u][i] * sumv % mod;///断开
for (int j = max(1, sz[v] + i - sz[u]);j <= min({ i, k,sz[v] });j++) ///链接
dp[u][i] = (dp[u][i] + 1LL * dp[u][i - j] * dp[v][j]) % mod;
}
}
} */ ///复杂度和常数比上面一种方式少一点,甚至比上面边界好写很多
void dfs(int u, int fa) {
dp[u][1] = 1;
sz[u] = 1;
for (auto v : g[u]) {
if (v == fa) continue;
dfs(v, u);
int sumv = 0;
for (int i = 1;i <= sz[v];i++) sumv = (sumv + dp[v][i]) % mod;
for (int i = min(sz[u], k);i >= 1;i--) {
for (int j = min(sz[v], k);j >= 1;j--) {
if (i + j > k) continue;///也可以用tmp暂存的方法,然后顺序更新,就可以直接break,否则只能倒叙
dp[u][i + j] = (dp[u][i + j] + 1LL * dp[u][i] * dp[v][j]) % mod;
}
dp[u][i] = 1LL * dp[u][i] * sumv % mod;
}
sz[u] += sz[v];
}
}///复杂度 O(nk^2),剪枝以后复杂度不变但常数会少巨多,因为少遍历了很多不可能的状态 int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k;
for (int i = 1;i < n;i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
int ans = 0;
for (int i = 1;i <= k;i++) ans = (ans + dp[1][i]) % mod;
cout << ans << '\n';
return 0;
}

NC20811 蓝魔法师的更多相关文章

  1. 牛客网 Wannafly挑战赛27 蓝魔法师

    蓝魔法师 链接: https://www.nowcoder.com/acm/contest/215/C 来源:牛客网 题目描述 "你,你认错人了.我真的,真的不是食人魔."--蓝魔 ...

  2. Wannafly挑战赛27 C蓝魔法师

    链接Wannafly挑战赛27 C蓝魔法师 给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于\(k\),\(n,k\leq 2*10^3\) 假设我们正在考虑\(i\)这个子树,那么 ...

  3. Wannafly挑战赛27

    Wannafly挑战赛27 我打的第一场$Wannafly$是第25场,$T2$竟然出了一个几何题?而且还把我好不容易升上绿的$Rating$又降回了蓝名...之后再不敢打$Wannafly$了. 由 ...

  4. BZOJ-5055-膜法师(离散化+树状数组)

    Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然,他能为长者所续的时间,为这三个维度上能量的乘 ...

  5. [BZOJ 5055]膜法师

    Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然,他能为长者所续的时间,为这三个维度上能量的乘 ...

  6. bzoj5055 膜法师

    Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然,他能为长者所续的时间,为这三个维度上能量的乘 ...

  7. BZOJ_5055_膜法师_树状数组+离散化

    BZOJ_5055_膜法师_树状数组+离散化 Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然 ...

  8. bzoj 5055: 膜法师——树状数组

    Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然,他能为长者所续的时间,为这三个维度上能量的乘 ...

  9. bzoj 5055: 膜法师 -- 树状数组

    5055: 膜法师 Time Limit: 10 Sec  Memory Limit: 128 MB Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇 ...

  10. JZOJ.5280【NOIP2017模拟8.15】膜法师

    Description

随机推荐

  1. Oracle数据库如何解决创建用户名开头必须要C##问题?

    1.问题 我们在创建用户,概要文件等时,由于使用的是容器数据库,其文件名必须以C##开头. 我们在学习过程中暂时不需要对齐进行区分,所以如何修改这个设定呢? 2.解决 参考链接如何解决创建用户名开头必 ...

  2. Go-使用本地时间解析时间字符串

    字符串 ==> time.Time package main import ( "fmt" "log" "time" ) func m ...

  3. [转帖]Prometheus-使用python开发exporter

    exporter有很多,但想要特定需求的话,还需自行开发.在这里使用python写一个exporter,用于监控/root下的目录数量. 开发exporter需要使用prometheus_client ...

  4. [转帖]kafka-console-ui v1.0.6发布

    前言 kafka-console-ui 是一款web版的kafka管理平台,从第一次发布到现在已经两年了,断断续续也更新了7个版本了(v1.0.0~v1.0.6). 一些常用的功能也陆续完善了不少,相 ...

  5. [转帖]RPC 框架总结与进阶

    https://www.cnblogs.com/xiaojiesir/p/15579418.html 框架总结 Netty 服务端启动 Netty 提供了 ServerBootstrap 引导类作为程 ...

  6. 【原创】关于xenomai3 RTnet的一点记录

    xenomai3协议栈RTnet支持TCP.UDP,但不支持IGMP: 对ARP支持有限制:地址解析的延迟会影响数据包传输延迟,RTnet为实时性考虑,路由表设计静态的,只在设置期间配置,或者接收到其 ...

  7. docker -- images镜像消失问题排查

    1. 问题描叙 安装model-serving组件时,错误日志输出push时对应的tag不存在,导致镜像推送失败 2. 问题排查 # 找到对应镜像,尝试手动推送 docker images|grep ...

  8. Spring 应用合并之路(一):摸石头过河 | 京东云技术团队

    公司在推进降本增效,在尝多种手段之后,发现应用太多,每个应用都做跨机房容灾部署,则最少需要 4 台机器(称为容器更合适).那么,将相近应用做一个合并,减少维护项目,提高机器利用率就是一个可选方案. 经 ...

  9. 在web中,用户输入的文字过多 和页面排版一行显示不下 怎么办

    在写管理系统中, 如果用户在input中,表单输入过多,应该如何去处理 常用的解决办法是: 1==>用户只能够输入一定范围内的字数 2==>超出几个字后(宽度)使用省略号显示. 3==&g ...

  10. uni-app 实现下拉刷新功能

    我们在运用uni-app开发小程序或h5时,常常需要页面实现下拉刷新功能. 在 js 中定义 onPullDownRefresh 处理函数(和onLoad等生命周期函数同级),监听该页面用户下拉刷新事 ...