@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」小星星的更多相关文章

  1. 「LOJ2091」「ZJOI2016」小星星 容斥+DP

    题目描述 小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有\(n\)颗小星星,用 \(m\)条彩色的细线串了起来,每条细线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉 ...

  2. @loj - 2090@ 「ZJOI2016」旅行者

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 来到了一个新的城市旅行.她发现了这个城市的布局是网格状的 ...

  3. loj2091 「ZJOI2016」小星星

    ref 总的来说,就是 容斥转化为点对应到点集问题. 树形 dp 解决转化后的问题. #include <iostream> #include <cstring> #inclu ...

  4. 「ZJOI2016」小星星

    传送门 Description Solution 容斥,考虑有多少个节点不被匹配到,求出的方案,多个点可以同时不被匹配到 状态压缩+树形dp Code  #include<bits/stdc++ ...

  5. @loj - 2093@ 「ZJOI2016」线段树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...

  6. @loj - 2092@ 「ZJOI2016」大森林

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 家里有一个大森林,里面有 n 棵树,编号从 1 到 n. ...

  7. 「ZJOI2016」解题报告

    「ZJOI2016」解题报告 我大浙的省选题真是超级神仙--这套已经算是比较可做的了. 「ZJOI2016」旅行者 神仙分治题. 对于一个矩形,每次我们从最长边切开,最短边不会超过 \(\sqrt{n ...

  8. Loj #3042. 「ZJOI2019」麻将

    Loj #3042. 「ZJOI2019」麻将 题目描述 九条可怜是一个热爱打麻将的女孩子.因此她出了一道和麻将相关的题目,希望这题不会让你对麻将的热爱消失殆尽. 今天,可怜想要打麻将,但是她的朋友们 ...

  9. 2090. 「ZJOI2016」旅行者 分治,最短路

    2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+dis(g ...

随机推荐

  1. Mac 安装package control

    参考网址:https://packagecontrol.io/installation 复制命令就不说明了. 主要阐述下第二种,下载安装包覆盖的方法,下面不说话,依次截图.步骤可以查看参考网址 啰嗦一 ...

  2. SpringBoot+Shiro+mybatis整合实战

    SpringBoot+Shiro+mybatis整合 1. 使用Springboot版本2.0.4 与shiro的版本 引入springboot和shiro依赖 <?xml version=&q ...

  3. CentOS7 下的 firewall 用法

    1.firewalld的基本使用 启动: systemctl start firewalld 查看状态: systemctl status firewalld  停止: systemctl disab ...

  4. 全栈数据工程师养成攻略:Python 基本语法

    全栈数据工程师养成攻略:Python 基本语法 Python简单易学,但又博大精深.许多人号称精通Python,却不会写Pythonic的代码,对很多常用包的使用也并不熟悉.学海无涯,我们先来了解一些 ...

  5. git图形化

    在windows下安装git中文版客户端并连接gitlab 转载自:https://blog.whsir.com/post-1801.html 下载git Windows客户端 git客户端下载地址: ...

  6. Jboss 默认加载项目访问

    修改JBOSS的server.xml路径为: D:\Program Files\jboss-4.2.2.GA\server\default\deploy\jboss-web.deployer\serv ...

  7. 从Java到C++——union的使用方法

    版权声明:本文为博主原创文章,未经博主同意不得用于不论什么商业用途,转载请注明出处. https://blog.csdn.net/luoweifu/article/details/33342965 你 ...

  8. 关系数据库(ch.2)

    2.1.1 关系 域 笛卡儿积 关系 candiate key 如果一组属性值可以唯一的标识一个元祖,但是他的子集不行,那么这是一个候选码 关系可以由三种类型 基本关系 查询关系 视图 为关系附加如下 ...

  9. 洛谷P2327 [SCOI2005]扫雷 [2017年5月计划 清北学堂51精英班Day1]

    P2327 [SCOI2005]扫雷 题目描述 输入输出格式 输入格式: 第一行为N,第二行有N个数,依次为第二列的格子中的数.(1<= N <= 10000) 输出格式: 一个数,即第一 ...

  10. shared_from_this bad_weak_ptr的原因

    原因:创建类A的对象的时候没有用智能指针包裹,而是直接new的裸指针. enable_from_this 的使用与实现原理说明: shared_from_this()是enable_shared_fr ...