题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4455

https://loj.ac/problem/2091

题解

很不错的一道题。(不过在当时考场上应该是签到吧

有一种很显然是错的的树形 DP 方法:

令 \(dp[x][i]\) 表示树上 \(x\) 对于图上 \(i\) 这个点,然后转移的时候直接枚举 \(x\) 的孩子和 \(i\) 的孩子进行匹配。

这样显然会有很多重复配对(即树上的两个点配对图上同一个点)的。然后我就很快把这个算法给放弃了。

(应该多想想的;得到一个教训:想到一个假算法以后要看看有没有一个方法把这个算法给改成正确的

然后正解就非常妙了:因为既然会有重复配对,那么图上也一定会有没有被配对的点。所以可以考虑直接容斥一下有那些点没有被配对,这些点就是禁止选的了。

最终容斥完医护就可以得到正确答案了。

时间复杂度 \(O(2^nn^3)\)。


#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 17 + 7; int n, m, cnt;
ll ans;
int ban[N];
ll dp[N][N];
std::vector<int> g1[N], g2[N]; inline void dfs(int x, int fa = 0) {
for (int i = 1; i <= n; ++i) dp[x][i] = !ban[i];
int len = g2[x].size();
for (int ii = 0, y; ii < len; ++ii) if (y = g2[x][ii], y != fa) {
dfs(y, x);
for (int i = 1; i <= n; ++i) if (!ban[i]) {
int len = g1[i].size();
ll sum = 0;
for (int jj = 0, j; jj < len; ++jj) {
j = g1[i][jj];
sum += dp[y][j];
}
dp[x][i] = dp[x][i] * sum;
}
}
} inline void calc() {
dfs(1);
ll sum = 0;
for (int i = 1; i <= n; ++i) if (!ban[i]) sum += dp[1][i];
if (cnt & 1) ans -= sum;
else ans += sum;
} inline void dfs1(int x) {
if (x == n + 1) return calc();
ban[x] = 0, dfs1(x + 1);
ban[x] = 1, ++cnt, dfs1(x + 1), --cnt;
} inline void work() {
dfs1(1);
printf("%lld\n", ans);
} inline void init() {
read(n), read(m);
int x, y;
for (int i = 1; i <= m; ++i) read(x), read(y), g1[x].pb(y), g1[y].pb(x);
for (int i = 1; i < n; ++i) read(x), read(y), g2[x].pb(y), g2[y].pb(x);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

bzoj4455 & loj2091 [Zjoi2016]小星星 容斥原理+树形DP(+状压DP?)的更多相关文章

  1. 【BZOJ】1076 [SCOI2008]奖励关 期望DP+状压DP

    [题意]n种宝物,k关游戏,每关游戏给出一种宝物,可捡可不捡.每种宝物有一个价值(有负数).每个宝物有前提宝物列表,必须在前面的关卡取得列表宝物才能捡起这个宝物,求期望收益.k<=100,n&l ...

  2. CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

  3. hdu 4352 "XHXJ's LIS"(数位DP+状压DP+LIS)

    传送门 参考博文: [1]:http://www.voidcn.com/article/p-ehojgauy-ot.html 题解: 将数字num字符串化: 求[L,R]区间最长上升子序列长度为 K ...

  4. [转]状态压缩dp(状压dp)

    状态压缩动态规划(简称状压dp)是另一类非常典型的动态规划,通常使用在NP问题的小规模求解中,虽然是指数级别的复杂度,但速度比搜索快,其思想非常值得借鉴. 为了更好的理解状压dp,首先介绍位运算相关的 ...

  5. 状态压缩dp 状压dp 详解

    说到状压dp,一般和二进制少不了关系(还常和博弈论结合起来考,这个坑我挖了还没填qwq),二进制是个好东西啊,所以二进制的各种运算是前置知识,不了解的话走下面链接进百度百科 https://baike ...

  6. 洛谷 P3343 - [ZJOI2015]地震后的幻想乡(朴素状压 DP/状压 DP+微积分)

    题面传送门 鸽子 tzc 竟然来补题解了,奇迹奇迹( 神仙题 %%%%%%%%%%%% 解法 1: 首先一件很明显的事情是这个最小值可以通过类似 Kruskal 求最小生成树的方法求得.我们将所有边按 ...

  7. BZOJ 4455: [Zjoi2016]小星星 [容斥原理 树形DP]

    4455: [Zjoi2016]小星星 题意:一个图删掉一些边形成一棵树,告诉你图和树的样子,求让图上的点和树上的点对应起来有多少方案 看了很多题解又想了一段时间,感觉题解都没有很深入,现在大致有了自 ...

  8. 51nod 1673 树有几多愁(链表维护树形DP+状压DP)

    题意 lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出 ...

  9. BZOJ3836 [Poi2014]Tourism 【树形dp +状压dp】

    题目链接 BZOJ3836 题解 显然这是个\(NP\)完全问题,此题的解决全仗任意两点间不存在节点数超过10的简单路径的性质 这意味着什么呢? \(dfs\)树深度不超过\(10\) \(10\)很 ...

随机推荐

  1. php接受post传值的方法

    这段时间在研究php的接口,利用jmeter模拟发送数据给php服务器,看php如何接收post传输过去的数据,遇到了几个问题,经过一番度娘之后终于有所理解,记录一下: 这里记录常用的两种post方式 ...

  2. ES6中的export和import

    1.ES6中的模块加载 ES6 模块是编译时加载,编译时就能确定模块的依赖关系,以及输入和输出的变量,相比于CommonJS 和 AMD 模块都只能在运行时确定输入输出变量的加载效率要高. 1.1.严 ...

  3. [NOI2014] 魔法森林 (二分答案,并查集)

    本思路仅供参考,数据强一点应该该会被卡. 本蒟蒻没有打 \(link\) - \(cut\) - \(tree\) . 而是用暴力水了过去. 具体思路很简单,先二分最少的 \(a_i\) , 再在 \ ...

  4. 用 margin 还是用 padding ?

    边界(margin):元素周围生成额外的空白区."空白区"通常是指其他元素不能出现且父元素背景可见的区域. 补白(padding):补白位于元素框的边界与内容区之间.很自然,用于影 ...

  5. sql常用 语句总结

    一,插入一个新字段:ALTER TABLE +表名+ADD  COLUMN(字段名+ 类型) sql1 = 'ALTER TABLE klkl_4s_shop ADD COLUMN (name_rea ...

  6. random、os、时间模块

    一.random 模块 1.随机小数 random.random()   #产生大于0且小于1之间的小数 random.uniform(1,3)   #产生1到3之间的随机小数 2.随机整数 rand ...

  7. jmeter之2种方法录制脚本

    有时候候录制脚本比写脚本且快,这时候我们可以采用录制的方法完成jmeter脚本工作 目录 1.badboy录制 2.代理服务器录制 1.badboy录制 第一步:下载安装 badboy2.2下载:链接 ...

  8. elasticsearch 5.1 认证过期 (your license has expired)

    首先说一下License过期后的状况: if 设置了登录认证,license过期后将无法登录(无法填入用户名密码,下方给出报错,license过期): if 没有设置登录认证,打开kibaba界面中M ...

  9. 第1 章 mysql数据库之简单的DDL和DML sql语句

    一.SQL 介绍 1.什么是sql? SQL,英文全称(Structured Query Language),中文是结构化查询语言,它是一种对关系数据库中数据进行定义和操作的语言方法,是大多数关系数据 ...

  10. Orcle获取当前时间加小时

    如下是oracle 获取当前数据库时间加2个小时 select to_date(TO_CHAR (SYSDATE, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24: ...