传送门

解题思路

  首先题目中有两个限制,第一个是两个集合直接必须一一映射,第二个是重新标号后,\(B\)中两点有边\(A\)中也必须有。发现限制\(2\)比较容易满足,考虑化简限制\(1\)。令\(f(S)\)表示重标号后至多出现在\(S\)中的标号且满足条件\(2\)的方案数,令\(g(S)\)表示重标号后恰好出现在\(S\)中的标号满足条件\(2\)的方案数。这应该是容斥里的一个套路。那么有转移方程:

\[f(S)=\sum\limits_{T \subseteq S}g(T)\Rightarrow g(S)=\sum\limits_{T \subseteq S}(-1)^{\left|S\right |-\left|T\right|}f(T)
\]

  然后问题就转化成为求\(f(S)\)了。令\(h[i][j]\)表示\(i\)点重新标号后是\(j\)的方案数。那么转移的时候考虑\(x\)的儿子\(u\)产生的贡献,可以枚举\(u\)的重标号,然后看他们两个的重标号之间有没有边,如果有的话\(cnt+=h[u][j]\),最后\(u\)对\(h[i][j]\)的贡献就为\(cnt\)。时间复杂度\(O(2^n*n^3)\),在下人丑常数大,\(bzoj\)卡了半天才过。。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib> using namespace std;
const int MAXN = 18;
typedef long long LL; inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
} int n,m,head[MAXN],cnt,a[MAXN][MAXN],zz[MAXN];
int to[MAXN<<1],nxt[MAXN<<1],tot;
LL g[MAXN][MAXN],ans,now;
bool use[MAXN]; void out(LL x){
if(!x) return ;
out(x/10);putchar('0'+x%10);
} inline void add(int bg,int ed){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
} void dfs(int x,int f){
int u;LL sum;
for(register int i=1;i<=tot;i++) g[x][i]=1;
for(register int i=head[x];i;i=nxt[i]){
u=to[i];if(u==f) continue;dfs(u,x);
for(register int j=1;j<=tot;j++){sum=0;
for(register int k=1;k<=tot;k++)
if(a[zz[j]][zz[k]]) sum+=g[u][k];
g[x][j]*=sum;
}
}
} int main(){
n=rd(),m=rd();int x,y;
for(register int i=1;i<=m;i++){
x=rd(),y=rd();
a[x][y]=a[y][x]=1;
}
for(register int i=1;i<n;i++){
x=rd(),y=rd();
add(x,y),add(y,x);
}int num;
for(register int S=1;S<1<<n;S++){
tot=0;num=0;now=0;
for(register int i=1,T=S;T;T>>=1,i++)
if(T&1) num++,zz[++tot]=i;
num=n-num;dfs(1,0);for(register int i=1;i<=tot;i++) now+=g[1][i];
if(num&1) ans-=now;else ans+=now;
}
if(!ans) putchar('0');else out(ans);
return 0;
}

最新文章

  1. java 21 - 2 字符输出流
  2. 【转】Kettle集群
  3. 从while(cin&gt;&gt;a)开始探讨cin
  4. 微信小店开发(2) DIY货架
  5. 使用drawBitmapMesh扭曲图像
  6. [开发笔记]-js判断用户的浏览设备是移动设备还是PC
  7. c语言编程中%g是什么格式
  8. Java多线程之简单的线程同步实例
  9. ios推送基于YII第三方组件的类库
  10. Filter plugins ? mutate:
  11. CSU 1021 从m个不同元素中取出n (n ≤ m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数。组合数的计算公式如下: C(m, n) = m!/((m - n)!n!) 现在请问,如果将组合数C(m, n)写成二进制数,请问转这个二进制数末尾有多少个零。
  12. 《第一行代码》学习笔记14-UI(3)
  13. linux学习笔记之文件结构和函数
  14. 项目代码摘抄,dot的用法之1
  15. ant svn
  16. .NET:国际化和本地化
  17. STL-Vector源码剖析
  18. 理解OpenShift(5):从 Docker Volume 到 OpenShift Persistent Volume
  19. SQLite reset password
  20. [转帖]Mysql 开启跟踪的一个方法

热门文章

  1. vue指令系统
  2. Django之Form操作
  3. [人物存档]【AI少女】【捏脸数据】朴素风格
  4. JMeter Http请求之content-type用法
  5. LUOGU P5061 秘密任务(背包+二分图染色)
  6. 利用爬虫爬取指定用户的CSDN博客文章转为md格式,目的是完成博客迁移博文到Hexo等静态博客
  7. Linux启动过程的C语言代码分析
  8. \t \r \n转义字符
  9. 前端(二十三)—— Vue环境搭建
  10. MySql 主从复制及深入了解