@loj - 2091@ 「ZJOI2016」小星星
@description@
小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有 n 颗小星星,用 m 条彩色的细线串了起来,每条细线连着两颗小星星。
有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了 n-1 条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。
小 Y 找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。
小 Y 想知道有多少种可能的对应方式。只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。
输入格式
第一行包含两个正整数 n,m,表示原来的饰品中小星星的个数和细线的条数。
接下来 m 行,每行包含两个正整数 u,v,表示原来的饰品中小星星 u 和 v 通过细线连了起来。
这里的小星星从 1 开始标号。保证 u ≠ v,且每对小星星之间最多只有一条细线相连。 接下来 n-1 行,每行包含两个正整数 u,v,表示现在的饰品中小星星 u 和 v 通过细线连了起来。保证这些小星星通过细线可以串在一起。
输出格式
输出共一行,包含一个整数表示可能的对应方式的数量。
如果不存在可行的对应方式则输出 0。
样例输入
4 3
1 2
1 3
1 4
4 1
4 2
4 3
样例输出
6
数据范围与提示
对于所有的数据,n <= 17, m <= n*(n-1)/2。
@solution@
普通的做法人人都会:定义 dp[i][j][s] 表示以 i 为根的子树,i 对应 j,这棵子树内已经用了集合 s 的点。
然后一波枚举子集转移。然后就炸了。
我没试过 FWT 行不行,不过好像比下面的算法多个 n 的复杂度,所以估计过不了。
考虑抽象问题模型:我们要找的其实是一个满足 “树边的两个端点对应过去也存在边” 这一限制的置换。
问题在于,置换必须要满足每个元素恰好被对应一次,所以我们才要枚举子集啊之类。
但其实只有一条边相邻两个点才会产生限制。因此我们直接统计置换是很吃亏的。
我们可以把置换看成 n 个点都要被对应,通过容斥转成只有 m 个点可以被对应。
形式化来说,假如我们可被对应的点的集合为 S。
我们的原问题相当于 S 中每一个点都要被对应,通过容斥转为 T 中的点可以被对应,其中 \(T\subset S\)。
那么就回到我们一开始的树形 dp,只是少了 s 这一维,变成 dp[i][j] 表示以 i 为根的子树,i 对应 j 的方案数。
外层容斥 \(O(2^n)\),树形 dp 的复杂度为 \(O(n^3)\),所以总时间复杂度为 \(O(2^n*n^3)\)。
@accepted code@
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
vector<int>G[20];
void addedge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
bool tag[20];
int A[20][20], n, m;
ll dp[20][20];
void dfs(int x, int f) {
for(int i=0;i<G[x].size();i++)
if( G[x][i] != f ) dfs(G[x][i], x);
for(int i=0;i<n;i++)
if( tag[i] ) {
dp[x][i] = 1;
for(int j=0;j<G[x].size();j++) {
int p = G[x][j];
if( p == f ) continue;
ll del = 0;
for(int k=0;k<n;k++)
if( A[i][k] ) del += dp[p][k];
dp[x][i] *= del;
}
}
else dp[x][i] = 0;
}
int f[1<<20];
int main() {
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++) {
int u, v; scanf("%d%d", &u, &v), u--, v--;
A[u][v] = A[v][u] = true;
}
for(int i=1;i<n;i++) {
int u, v; scanf("%d%d", &u, &v), u--, v--;
addedge(u, v);
}
int t = (1<<n); f[0] = 1;
for(int i=1;i<t;i++)
f[i] = (i&1) ? -f[i>>1] : f[i>>1];
ll ans = 0;
for(int s=0;s<t;s++) {
for(int i=0;i<n;i++)
tag[i] = !((s>>i) & 1);
dfs(0, -1);
for(int i=0;i<n;i++)
if( tag[i] ) ans = ans + f[s]*dp[0][i];
}
printf("%lld\n", ans);
}
@details@
ZJOI 的题都是神仙题 * 2。
代码倒是非常简洁。
@loj - 2091@ 「ZJOI2016」小星星的更多相关文章
- 「LOJ2091」「ZJOI2016」小星星 容斥+DP
题目描述 小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有\(n\)颗小星星,用 \(m\)条彩色的细线串了起来,每条细线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉 ...
- @loj - 2090@ 「ZJOI2016」旅行者
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 来到了一个新的城市旅行.她发现了这个城市的布局是网格状的 ...
- loj2091 「ZJOI2016」小星星
ref 总的来说,就是 容斥转化为点对应到点集问题. 树形 dp 解决转化后的问题. #include <iostream> #include <cstring> #inclu ...
- 「ZJOI2016」小星星
传送门 Description Solution 容斥,考虑有多少个节点不被匹配到,求出的方案,多个点可以同时不被匹配到 状态压缩+树形dp Code #include<bits/stdc++ ...
- @loj - 2093@ 「ZJOI2016」线段树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...
- @loj - 2092@ 「ZJOI2016」大森林
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 家里有一个大森林,里面有 n 棵树,编号从 1 到 n. ...
- 「ZJOI2016」解题报告
「ZJOI2016」解题报告 我大浙的省选题真是超级神仙--这套已经算是比较可做的了. 「ZJOI2016」旅行者 神仙分治题. 对于一个矩形,每次我们从最长边切开,最短边不会超过 \(\sqrt{n ...
- Loj #3042. 「ZJOI2019」麻将
Loj #3042. 「ZJOI2019」麻将 题目描述 九条可怜是一个热爱打麻将的女孩子.因此她出了一道和麻将相关的题目,希望这题不会让你对麻将的热爱消失殆尽. 今天,可怜想要打麻将,但是她的朋友们 ...
- 2090. 「ZJOI2016」旅行者 分治,最短路
2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+dis(g ...
随机推荐
- Comparator进行List集合排序
对数据库中查询到的结果进行排序,一般开发中,实体类是没有实现Comparable接口的,所以不能实现compareTo()方法进行排序, 只能用Comparator去进行排序,只需要在带排序的集合中加 ...
- JSP-Cookie和Session
1 会话技术简介 1.1 存储客户端状态 1.2 会话技术 2 Cookie技术 2.1 Cookie技术的购物 2.2 服务器端向客户端发Cookie //1.创建cookie对象 Cookie c ...
- 禁用/移除WordPress页面的评论功能
对于某些类型的WordPress站点,也许不需要在页面(page)提供评论功能,那么你可以通过下面的方法,很容易就禁用或移除WordPress页面的评论功能. 方法1:在页面编辑界面取消该页面的评论功 ...
- 模拟4题解 T3奇袭
T3奇袭 题目描述 由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上 要迎来最终的压力测试——魔界入侵. 唯一一个神一般存在的Administrator被消灭了,靠原本 ...
- oracle 控制结构
1.if 逻辑结构 if/then 结构是最简单的条件测试,如果条件为真,则执行程序的一行或者多行,如果条件为假,则什么都不执行, 示例: if 1>2 then null; end if ; ...
- shell 向python传参数,空格引发的问题
昨天用一个shell脚本,调用一个python脚本,并把shell脚本中用 time1=`date "+%Y-%m-%d %H:%M:%S"`生成的时间戳作为参数,传到python ...
- 你真的了解HTML吗
有这么一段HTML,请挑毛病: <P> 哥写的不是HTML,是寂寞.<br><br> 我说: <br>不要迷恋哥,哥只是一个传说 这是原来雅虎一道笔试题 ...
- C++ 之手写memcpy
#include<iostream>#include<cstdio>using namespace std; void* mymemcpy(void* dst, const v ...
- 使用淘宝镜像cnpm安装Vue.js
简介: Vue.js是前端一个比较火的MVVM框架, 是一套构建用户界面的渐进式框架. Vue 只关注视图层, 采用自底向上增量开发的设计. Vue 的目标是通过尽可能简单的 API 实现响应的数据绑 ...
- Spring_JDBC连接
1.导入jarbao 2.创建pojo,dao,Impl package com.tanlei.pojo; public class Department { private Long deptId; ...