首页 > 其他分享 >【容斥、状压dp】主旋律 题解

【容斥、状压dp】主旋律 题解

时间:2023-04-05 23:01:02浏览次数:38  
标签:subset int 题解 ll 状压 容斥 times

【清华集训2014】主旋律 题解

神秘题。

题目简述

  • 给你一个有向图 \(G=(V,E)\)。求有多少 \(E\) 的子集 \(E'\) 使得新图 \(G'=(V,E')\) 是强连通图。

  • 强连通图的定义是任意两点 \(u,v\) 均存在 \(u\to v,v\to u\) 的路径。

  • \(n\leq 15,m\leq n\times(n-1)\)。

解题思路

下面记点集 \(V_1\) 导出子图的答案为 \(f(V_1)\)。我们只要求 \(f(V)\)。我们考虑对每个点集 \(V_1\subset V\) 都求出 \(f(V_1)\)。

正难则反,我们考虑他不是强连通图的方案。非强联通图缩点以后是一个 DAG,我们考虑枚举 DAG 当中所有入度为 \(0\) 的点,然后容斥即可。

更具体的,我们需要枚举所有入度为 \(0\) 的强连通分量 \(V'\subset V\),定义 \(g(V')\) 为选取的方案数,那么剩下的任务就是在 \(e^{\dagger}[V'\to V/V']\) 和 \(e[V/V'\to V/V']\)。这些边是可以任意选取的。我们不需要担心重复的问题,这应该在 \(g\) 当中就解决掉。

\(^{\dagger}\) \(e[U\to V]\) 表示起点在点集 \(U\) 终点在点集 \(V\) 的有向边数量。

总结一下上面也就是:

\[f(V)=2^{e[V\to V]}-\sum_{V_1\subset V} g(V_1)\times 2^{e[V\to V/V']} \]

我们再考虑 \(g(V)\) 的计算方法。\(g(V)\) 的另一种理解是缩点后两两不联通的方案再去乘上容斥系数(偶数个连通分支为 \(-1\),奇数个为 \(1\)),我们去枚举一个连通分支就可以了。也就是:

\[g(V)=\sum_{V_1\subset V,u\in V_1} -f(V_1)\times g(V-V_1) \]

其中 \(u\) 是随意选取的一个 \(V\) 中的点。要注意的是 \(V_1\) 可能等于 \(V\),所以要先计算 \(f(V)\)。

至此这题便做完了。时间复杂度 \(O(3^n\times n)\)。

参考代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD=1e9+7;
int n,m;
int a[20];
ll pw[205],f[1<<16],g[1<<16];
int popcount(int x){int cnt=0;while(x)cnt++,x-=(x&-x);return cnt;}
int edge(int u,int v){
	int cnt=0;
	for(int i=0;i<n;i++)if(u>>i&1)cnt+=popcount(a[i]&v);
	return cnt;
}
void del(ll &x,ll y){x-=y;if(x<0)x+=MOD;}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		a[u-1]|=(1<<v-1);
	}
	pw[0]=1;
	for(int i=1;i<205;i++) pw[i]=pw[i-1]*2%MOD;
	for(int i=1;i<(1<<n);i++){
		int t=(i&-i),k=i^t;// 固定一个点
		for(int j=(k-1)&k;j;j=(j-1)&k) del(g[i],g[k^j]*f[j|t]%MOD);
		if(t!=i) del(g[i],g[k]);
		f[i]=pw[edge(i,i)];
		for(int j=i;j;j=(j-1)&i) del(f[i],g[j]*pw[edge(i,i^j)]%MOD);
		g[i]+=f[i];g[i]%=MOD;
	}
	cout<<f[(1<<n)-1];
	return 0;
}

标签:subset,int,题解,ll,状压,容斥,times
From: https://www.cnblogs.com/KawaiiOU/p/17291234.html

相关文章

  • GMOI R2 T2 猫耳小(加强版) 官方题解
    首先特判\(k=0\)的情况,此时的答案为非\(0\)数的个数,改法是将它们全改成\(0\)。再特判\(k\)较大的情况,此时的答案为\(0\)。否则,对于\(k\)大小适中的情况,我们从前往后遍历数组,同时维护当前区间的\(\operatorname{mex}\)值。根据\(\operatorname{mex}\)的定义,显然对......
  • [HAOI2007]理想的正方形【题解】
    题目描述有一个\(a\timesb\)的整数组成的矩阵,现请你从中找出一个\(n\timesn\)的正方形区域,使得该区域所有数中的最大值和最小值的差最小。输入格式第一行为\(3\)个整数,分别表示\(a,b,n\)的值。第二行至第\(a+1\)行每行为\(b\)个非负整数,表示矩阵中相应位置上......
  • 奶牛排队【题解】
    题目描述奶牛在熊大妈的带领下排成了一条直队。显然,不同的奶牛身高不一定相同……现在,奶牛们想知道,如果找出一些连续的奶牛,要求最左边的奶牛\(A\)是最矮的,最右边的\(B\)是最高的,且\(B\)高于\(A\)奶牛。中间如果存在奶牛,则身高不能和\(A,B\)奶牛相同。问这样的奶牛最......
  • AT CODE FESTIVAL 2016 Final J 题解
    题目妙妙题!简要题意:给定一个\(n\),有一个\(n\timesn\)的网格图。有\(4n\)个方向\(U/D/L/R_{1,2,\dots,n}\),如下图:对于每个方向,有个限制:数\(x\)。你可以进行\(\lex\)次推棋子,把一个棋子放到当前方向指向的第一格,然后如果原来第一格有棋子,把它放到第二格,如果原来第二......
  • 【问题解决】eclipse cdt debug状态控制台输出中文部分乱码
    问题复现使用eclipsecdt版本写了一个C代码简易输出的程序如下:#include<stdio.h>#include<stdlib.h>voidprintln(chararr[]){ inti=0; while(arr[i]!='\0'){ printf("%c",arr[i]); i++; } printf("\n");}intmain(void){......
  • 状压DP
    [acwing]291.蒙德里安的梦想/* 横放的方案数就等于总方案数,因为横着放完后,再竖着放是唯一的 dp[i][j]表示第i列状态为j的方案数 状态为j是指:各行用0或1表示摆放状态 :若某行为0,表示竖放或由前一列伸出 :若某行为1,表示横放并向后一列伸出 ......
  • FWT & FMT & 集合幂级数 题解集
    CF449DJzzhuandNumbers简要题意给定序列\(\{a_n\}\),求有多少个子序列满足所有元素的按位与为\(0\)。题解F1考虑FWT的与卷积形式,构造序列\(\{A_n\}\),使\(A_i=\displaystyle\sum_{j\&i=i}a_i\),记\(B_i=\displaystyle\sum_{b\ina}[(b_1\&b_2\&\cdots\&b_n)\&......
  • 2023GPLT选拔题解
    看到没有题解我就给大家浅浅的写一篇吧,如果有错误,希望大家可以帮我指出来哦,创作不易,如果大家给个关注,点个赞就更好了  1:著名开源操作系统Linux的核心创始人Linus有一句经典名言:”Talkischeap.Showmethecode.“ 说出这句话时是2000年8月25日,那天有人在Linus的Linu......
  • 查看hbase表没有,但是新建却显示存在这个表的问题解决方案
    转:https://blog.csdn.net/leng91060404/article/details/106956315zookeeper数据存储及查看hbase信息1.zookeeper数据存储:1.1内存数据存储、磁盘数据存储.    内存数据存储:    数据模型是一棵树。包括所有节点路径,节点信息,ACL等。    DataTree:所有节点信息  ......
  • 洛谷 P3377 【模板】左偏树(可并堆)题解 左偏树模板题
    题目链接:https://www.luogu.com.cn/problem/P3377维护左偏树的同时还需要维护一个并查集。但是并查集也就一个find操作。pop的时候更新f[x]的操作很神奇。示例程序:#include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e5+5;intn,m,op,x,y,val[m......