题目描述

小 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. 趣味编程:FizzBuzz(Haskell版)

    g :: Int -> Int -> Int -> String g n 0 0 = "FizzBuzz" g n 0 _ = "Fizz" ...

  2. hdu6172&&hdu6185&&P5487——BM算法

    hdu6172 模板的简单应用 先根据题中的表达式求出前几项,再上BM,注意一下n的大小关系. #include <bits/stdc++.h> using namespace std; ...

  3. 65、Spark Streaming:数据接收原理剖析与源码分析

    一.数据接收原理 二.源码分析 入口包org.apache.spark.streaming.receiver下ReceiverSupervisorImpl类的onStart()方法 ### overr ...

  4. C博客作业02——循环结构

    0.展示PTA总分 单循环题目集 嵌套循环题目集 1.本章学习总结 1.1学习内容总结 (a)while语句 while(表达式) { 循环体语句: } 执行流程:当表达式的值为"真&quo ...

  5. 3D数据采集和重建

    3D数据采集和重建是从传感器数据生成三维或时空模型.一般而言,这些技术和理论适用于大多数或所有传感器类型,包括光学,声学,激光扫描,[1]雷达,热学,[2]地震.[3][4] 内容 ·        ...

  6. D3.js的v5版本入门教程(第三章)—— 选择元素和绑定数据

    D3.js的v5版本入门教程(第三章) 在D3.js中,选择元素和绑定元素是最基本的内容,也是很重要的内容,等你看完整个教程后你会发现,这些D3.js教程都是在选择元素和绑定元素的基础上展开后续工作的 ...

  7. Linux 权限规划ACL

    什么是ACL ACL是Access Control List的缩写,主要目的是提供传统的owner.group.others的read.write.execute权限之外的具体权限设置 ACL可以针对 ...

  8. Confd+Consul 动态生成配置文件

    一.Consul安装和配置 1.consul是什么? consul是HashiCorp公司推出的一款工具,主要用于实现分布式系统的服务发现与配置,它提供了以下几个关键特性: 服务发现:Consul客户 ...

  9. 20189220 余超《Linux内核原理与分析》第三周作业

    操作系统如何工作的 第二章的基础知识 计算机的三大法宝:存储程序计算机,函数调用堆栈机制,中断. 堆栈:堆栈是C语言程序运行时必须使用的几率函数条用路径和参数存储的空间,具体作用分为:记录函数条用的框 ...

  10. 【转】URL短地址压缩算法 微博短地址原理解析 (Java实现)

    转自: URL短地址压缩算法 微博短地址原理解析 (Java实现) 最近,项目中需要用到短网址(ShortUrl)的算法,于是在网上搜索一番,发现有C#的算法,有.Net的算法,有PHP的算法,就是没 ...