bzoj4455 & loj2091 [Zjoi2016]小星星 容斥原理+树形DP(+状压DP?)
时间:2019-09-27
本文章向大家介绍bzoj4455 & loj2091 [Zjoi2016]小星星 容斥原理+树形DP(+状压DP?),主要包括bzoj4455 & loj2091 [Zjoi2016]小星星 容斥原理+树形DP(+状压DP?)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=4455
题解
很不错的一道题。(不过在当时考场上应该是签到吧
有一种很显然是错的的树形 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;
}
原文地址:https://www.cnblogs.com/hankeke/p/bzoj4455.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 非常有必要了解的Springboot启动扩展点
- 冒泡排序图解+代码示例
- 使用prepareStatement连接数据库实现增、删、改、查
- 插入排序图解与代码示例
- 初步使用Druid连接池+代码示例:对图书进行增删改查
- 创建Servlet的几种方式+web.xml中关于servlet的一些配置+浏览器、服务器交互Postman测试
- 二分法查找介绍+代码
- API文档的自动生成
- cookie创建的三个参数(有效期+有效路径+httponly)
- interface概念与代码示例,常量接口和标记接口,与abstract的区别
- Java8异步编程就是拽
- 如果try{}里面有一个return语句,那么紧跟着这个try后的finally{}里面的代码会不会执行?
- 二叉查找树代码java+运行结果
- 全选
- 在控制台,递归显示文件夹下所有文件目录代码+ 运行结果