题目描述

小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有\(n\)颗小星星,用 \(m\)条彩色的细线串了起来,每条细线连着两颗小星星。有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了\(n-1\)条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小 Y 找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。小 Y 想知道有多少种可能的对应方式。只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。

输入

第一行包含两个正整数\(n,m\),表示原来的饰品中小星星的个数和细线的条数。

接下来\(n-1\)行,每行包含两个正整数\(u,v\),表示原来的饰品中小星星\(u\)和 \(v\)通过细线连了起来。

这里的小星星从 开始标号。保证 ,且每对a小星星之间最多只有一条细线相连。 接下来 行,每行包含两个正整数 ,表示现在的饰品中小星星 和 通过细线连了起来。保证这些小星星通过细线可以串在一起。

输出

输出共一行,包含一个整数表示可能的对应方式的数量。

如果不存在可行的对应方式则输出\(0\)。

样例

样例输入

4 3
1 2
1 3
1 4
4 1
4 2
4 3

样例输出

6

数据范围

对于所有的数据\(n\leq 17\),\(m\leq \frac{n(n-1)}{2}\)。

题解

首先,我诈尸了。

第二,这是道容斥原理好题目……

考虑这个问题的等价形式,对树上的点进行重标号,让重标号的点可以嵌入原图(即,树上相邻的点在原图也相邻),并且满足每个点不会有相同的编号,然后问重标号的方案数。

于是一个简单的状压\(DP\)就呼之欲出了:\(f[i][s]\)表示以\(i\)为根的子树,把\(s\)里的数全都标号了,方案数是多少?这个可以很容易地使用子集转移做到\(O(n^k3^n)\),\(k\)随你实现的方法有所变化,然而不管\(k\)取多少都没办法过……毕竟有一个\(3^n\)在那里。

我们似乎没有办法了,不如考虑没有“两个点的标号不能相同”这个限制,这就非常好做了,\(f[i][j]\)表示以\(i\)为根的子树的答案,并且\(i\)的标号是\(j\)的方案。状态转移方程式显然很好写:

\[f[i][j]=\prod_{s\in son_i}\left(\sum_{A_{k,j}=1}f[s][k]\right)
\]

然后这个东西显然会求出重复标号,我们稍微想想就知道可以容斥出来答案。\(2^n\)枚举一下哪些点不能被使用,奇数个就减掉,偶数个就加上,感性理解一下看起来是对的。很显然,强制要求一些点不选并不会增加\(DP\)难度,复杂度大约是\(O(n^32^n)\),我是不知道怎么继续优化了……用一些优化方式可以剪掉一些不必要的情况,卡卡常就过了。

\(Code:\)

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 20
#define ll long long
int n, m, A[N][N];
int tar[N << 1], nex[N << 1], fir[N], cnt;
ll f[N][N];
vector<int> ver[N];
void Add(int a, int b)
{
++cnt;
tar[cnt] = b;
nex[cnt] = fir[a];
fir[a] = cnt;
}
void Dfs(int r, int fa, int s)
{
for (int i = fir[r]; i; i = nex[i])
{
int v = tar[i];
if (v != fa)
Dfs(v, r, s);
}
for (int i = 1; i <= n; i++)
{
if (s & (1 << (i - 1)))
continue;
f[r][i] = 1;
for (int j = fir[r]; j; j = nex[j])
{
int v = tar[j];
if (v != fa) {
ll sum = 0;
int t = ver[i].size();
for (int k = 0; k < t; k++)
{
int p = ver[i][k];
if (s & (1 << (p - 1)))
continue;
sum += f[v][p];
}
f[r][i] *= sum;
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
ver[a].push_back(b);
ver[b].push_back(a);
}
for (int i = 1; i < n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
Add(u, v), Add(v, u);
}
ll ans = 0;
for (int i = 0; i < (1 << n); i++)
{
Dfs(1, 0, i);
ll sum = 0;
int bit = 1;
for (int j = 1; j <= n; j++)
if (i & (1 << (j - 1)))
bit = -bit;
else
sum += f[1][j];
ans += bit * sum;
}
printf("%lld\n", ans);
}

「LOJ2091」「ZJOI2016」小星星 容斥+DP的更多相关文章

  1. [BZOJ4455][ZJOI2016]数星星(容斥DP)

    4455: [Zjoi2016]小星星 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 707  Solved: 419[Submit][Status] ...

  2. 4455[Zjoi2016]小星星 容斥+dp

    4455: [Zjoi2016]小星星 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 527  Solved: 317[Submit][Status] ...

  3. HDU 5794 A Simple Chess (容斥+DP+Lucas)

    A Simple Chess 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 Description There is a n×m board ...

  4. [CF1086E]Beautiful Matrix(容斥+DP+树状数组)

    给一个n*n的矩阵,保证:(1)每行都是一个排列 (2)每行每个位置和上一行对应位置不同.求这个矩阵在所有合法矩阵中字典序排第几.考虑类似数位DP的做法,枚举第几行开始不卡限制,那么显然之前的行都和题 ...

  5. 【BZOJ3622】已经没有什么好害怕的了 容斥+DP

    [BZOJ3622]已经没有什么好害怕的了 Description Input Output Sample Input 4 2 5 35 15 45 40 20 10 30 Sample Output ...

  6. $bzoj2560$ 串珠子 容斥+$dp$

    正解:容斥+$dp$ 解题报告: 传送门$QwQ$ $umm$虽然题目蛮简练的了但还是有点难理解,,,我再抽象一点儿,就说有$n$个点,点$i$和点$j$之间有$a_{i,j}$条无向边可以连,问有多 ...

  7. loj#2542. 「PKUWC2018」随机游走(MinMax容斥 期望dp)

    题意 题目链接 Sol 考虑直接对询问的集合做MinMax容斥 设\(f[i][sta]\)表示从\(i\)到集合\(sta\)中任意一点的最小期望步数 按照树上高斯消元的套路,我们可以把转移写成\( ...

  8. LOJ#503. 「LibreOJ β Round」ZQC 的课堂(容斥+FHQTreap)

    题面 传送门 题解 首先\(x\)和\(y\)两维互相独立,可以分开考虑,我们以\(x\)为例 我们把\(x\)做个前缀和,那么就是问有多少\(i\)满足\(s_is_{i-1}<0\),其中\ ...

  9. loj2542 「PKUWC2018」随机游走 MinMax 容斥+树上高斯消元+状压 DP

    题目传送门 https://loj.ac/problem/2542 题解 肯定一眼 MinMax 容斥吧. 然后问题就转化为,给定一个集合 \(S\),问期望情况下多少步可以走到 \(S\) 中的点. ...

随机推荐

  1. Kafka为什么这么快?

    批量处理 传统消息中间件的消息发送和消费整体上是针对单条的.对于生产者而言,它先发一条消息,然后broker返回ACK表示已接收,这里产生2次rpc:对于消费者而言,它先请求接受消息,然后broker ...

  2. strcspn函数的用法

    #include <string.h> main() { char *str = "Linux was first developed for 386/486-based pcs ...

  3. 04-Flutter移动电商实战-打通底部导航栏

    关于界面切换以及底栏的实现可参考之前写的一篇文章:Flutter实 ViewPager.bottomNavigationBar界面切换 1.新建4个基本dart文件 在pages目录下,我们新建下面四 ...

  4. LeetCode 855. Exam Room

    原题链接在这里:https://leetcode.com/problems/exam-room/ 题目: In an exam room, there are N seats in a single ...

  5. LeetCode 923. 3Sum With Multiplicity

    原题链接在这里:https://leetcode.com/problems/3sum-with-multiplicity/ 题目: Given an integer array A, and an i ...

  6. 解决bash: less: command not found

    问题描述 使用less命令查找日志时,less命令未找到: 解决办法 安装less,执行如下命令: npm install -g less

  7. ThinkCMF框架任意内容包含

    更多内容,欢迎关注微信公众号:信Yang安全,期待与您相遇. ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建.ThinkCMF提出灵活的应用 ...

  8. python中序列的操作

    Python中的序列操作 可变对象:列表.字典.集合 不可变对象:数值.字符串.元组.forzenset 1.序列的通用操作 (1)测试元素是否存在 x in S和x not in S,返回True或 ...

  9. 【洛谷P4585】 [FJOI2015]火星商店问题 线段树分治+可持久化trie

    感觉这个线段树分治和整体二分几乎相同啊~ code: #include <bits/stdc++.h> #define MAX 100300 #define ll long long #d ...

  10. CF1172E Nauuo and ODT

    CF1172E Nauuo and ODT 神仙题orz 要算所有路径的不同颜色之和,多次修改,每次修改后询问. 对每种颜色\(c\)计算多少条路径包含了这个颜色,不好算所以算多少条路径不包含这个颜色 ...