【bzoj3812】【清华集训2014】主旋律(容斥,计数)

20 篇文章 0 订阅
11 篇文章 0 订阅

毒 瘤 计 数!

XSY 题意不是很清楚,这里给出更加清楚的:

给定一张 n n n 个点 m m m 条边的无向图,保证该图整个图为一个强联通分量,且无重边自环。现在需要求出:有多少种删边方案,使得删完边后,整个图依旧是一个强联通分量。数据范围: n ≤ 15 , m ≤ n ( n − 1 ) n\leq 15,m\leq n(n-1) n15,mn(n1)

E [ U , V ] E[U,V] E[U,V] 表示题目给的所有边中,起点在 U U U 中、终点在 V V V 中的所有边的集合,其中 U , V U,V U,V 为点集。

对于一个点集 S S S,设其任意形成的某一张图为 G G G(“形成”是指通过题目给的边形成),我们对其连边后缩点,最后得到的肯定是若干个强连通分量(称为 scc)之间有连边,形成一个 DAG。而题目要求的是只有一个 scc,那么我们就要用 S S S 能形成的图的总数量 2 E [ S , S ] 2^{E[S,S]} 2E[S,S] 减去 S S S 形成的图是多个 scc 的 DAG 的情况。

那么我们枚举这个 DAG 中,出度为 0 0 0 的那些 scc 所包含的点的集合 T T T,然后再考虑在确定了 T T T 的基础上再确定 G G G 的数量。

首先 S − T S-T ST(中间是减号)的点之间可以乱连, S − T S-T ST 的点向 T T T 的点也可以乱连,这部分的方案是 2 E [ S − T , S − T ] × 2 E [ S − T , T ] 2^{E[S-T,S-T]}\times 2^{E[S-T,T]} 2E[ST,ST]×2E[ST,T]

于是我们可以暂时建立一个等量关系:
2 E [ S , S ] = ∑ T ⊆ S , T ≠ ∅ g T × 2 E [ S − T , S − T ] × 2 E [ S − T , T ] 2^{E[S,S]}=\sum_{T\subseteq S,T\neq \emptyset}g_T\times 2^{E[S-T,S-T]}\times 2^{E[S-T,T]} 2E[S,S]=TS,T=gT×2E[ST,ST]×2E[ST,T]
其中 g T g_T gT 可以暂时理解为点集 T T T 形成的图为若干个强联通分量的方案数,但显然这样定义是不对的,原因下面会说。

f X f_X fX 表示点集 X X X 形成的图为一个强联通分量的方案数。(那么 f f f 就是题目所求)

那么就可以直接 g T = ∑ s 1 , s 2 , ⋯   , s k ∏ i = 1 k f s i g_T=\sum\limits_{s_1,s_2,\cdots,s_k}\prod\limits_{i=1}^k f_{s_i} gT=s1,s2,,ski=1kfsi 了吗?(其中 ∑ s 1 , s 2 , ⋯   , s k \sum\limits_{s_1,s_2,\cdots,s_k} s1,s2,,sk 的意思是将 T T T 划分为若干个scc s 1 , s 2 , ⋯   , s k s_1,s_2,\cdots,s_k s1,s2,,sk,即枚举 s 1 ∪ s 2 ∪ ⋯ ∪ s k = T s_1\cup s_2\cup\cdots\cup s_k=T s1s2sk=T 满足 ∀ i ≠ j , s i ∩ s j = ∅ \forall i\neq j,s_i\cap s_j=\emptyset i=j,sisj=

当然不行,因为 E [ S − T , S − T ] E[S-T,S-T] E[ST,ST] 里面的是随便连的,有可能会形成其他的出度为 0 0 0 的 scc,这与我们的假设不符,会导致算重。这也就是 g T g_T gT 不能直接定义为“点集 T T T 形成的图为若干个强联通分量的方案数”的原因。

因此我们需要容斥。于是设容斥系数 c o e f k coef_k coefk
g T = ∑ s 1 , s 2 , ⋯   , s k c o e f k ∏ i = 1 k f s i g_T=\sum\limits_{s_1,s_2,\cdots,s_k}coef_k\prod\limits_{i=1}^k f_{s_i} gT=s1,s2,,skcoefki=1kfsi
对于 T T T 的某一种划分方案 s 1 , s 2 , ⋯   , s k s_1,s_2,\cdots,s_k s1,s2,,sk,我们在 s 1 , s 2 , ⋯   , s k s_1,s_2,\cdots,s_k s1,s2,,sk 中任意选出若干个并起来得到 T ′ T' T,那么当我们在枚举 T = T ′ T=T' T=T 时,这种方案都被算了一次,于是这种方案实际上被算了:
∑ i = 0 k ( k i ) c o e f i \sum_{i=0}^k\binom{k}{i}coef_i i=0k(ik)coefi
理论上,这种方案应该只能被算一次,于是:
1 = ∑ i = 1 k ( k i ) c o e f i 1=\sum_{i=1}^k\binom{k}{i}coef_i 1=i=1k(ik)coefi
根据二项式反演:
c o e f k = ∑ i = 1 k ( − 1 ) k − i ( k i ) = ( ∑ i = 0 k ( k i ) 1 i ( − 1 ) k − i ) − ( − 1 ) k = ( 1 − 1 ) k − ( − 1 ) k = ( − 1 ) k + 1 \begin{aligned} coef_k&=\sum_{i=1}^k(-1)^{k-i}\binom{k}{i}\\ &=\left(\sum_{i=0}^k\binom{k}{i}1^i(-1)^{k-i}\right)-(-1)^k\\ &=(1-1)^k-(-1)^k\\ &=(-1)^{k+1} \end{aligned} coefk=i=1k(1)ki(ik)=(i=0k(ik)1i(1)ki)(1)k=(11)k(1)k=(1)k+1
于是:
g T = ∑ s 1 , s 2 , ⋯   , s k ( − 1 ) k + 1 ∏ i = 1 k f s i g_T=\sum\limits_{s_1,s_2,\cdots,s_k}(-1)^{k+1}\prod\limits_{i=1}^k f_{s_i} gT=s1,s2,,sk(1)k+1i=1kfsi
如果求出了 g g g,那么就能跟 f f f 扯上点关系。

根据我们刚开始那条式子可以对 g g g 进行递推:
2 E [ S , S ] = ∑ T ⊆ S , T ≠ ∅ g T × 2 E [ S − T , S − T ] × 2 E [ S − T , T ] g S = 2 E [ S , S ] − ∑ T ⫋ S , T ≠ ∅ g T × 2 E [ S − T , S − T ] × 2 E [ S − T , T ] \begin{aligned} 2^{E[S,S]}&=\sum_{T\subseteq S,T\neq \emptyset}g_T\times 2^{E[S-T,S-T]}\times 2^{E[S-T,T]}\\\\ g_S&=2^{E[S,S]}-\sum_{T\subsetneqq S,T\neq \emptyset}g_T\times 2^{E[S-T,S-T]}\times 2^{E[S-T,T]} \end{aligned} 2E[S,S]gS=TS,T=gT×2E[ST,ST]×2E[ST,T]=2E[S,S]TS,T=gT×2E[ST,ST]×2E[ST,T]
于是 g g g 求出来了。

观察刚刚推出来的 g g g f f f 的式子:
g T = ∑ s 1 , s 2 , ⋯   , s k ( − 1 ) k + 1 ∏ i = 1 k f s i g_T=\sum\limits_{s_1,s_2,\cdots,s_k}(-1)^{k+1}\prod\limits_{i=1}^k f_{s_i} gT=s1,s2,,sk(1)k+1i=1kfsi
那么:
g T = ( − 1 ) × ∑ s 1 ⊆ T , s 1 ≠ ∅ f s 1 g T − s 1 \begin{aligned} g_T=(-1)\times \sum_{s_1\subseteq T,s_1\neq \emptyset}f_{s_1}g_{T-s_1}\\ \end{aligned} gT=(1)×s1T,s1=fs1gTs1
(其中 s 1 s_1 s1 枚举的是 T T T 中编号最小的点所在的scc)

也由此可知应该令 g ∅ = − 1 g_{\emptyset}=-1 g=1

于是:
g T = f T + ( − 1 ) × ∑ s 1 ⫋ T , s 1 ≠ ∅ f s 1 g T − s 1 f T = g T + ∑ s 1 ⫋ T , s 1 ≠ ∅ f s 1 g T − s 1 \begin{aligned} g_T=f_T+(-1)\times\sum_{s_1\subsetneqq T,s_1\neq \emptyset}f_{s_1}g_{T-s_1}\\ f_T=g_T+\sum_{s_1\subsetneqq T,s_1\neq \emptyset}f_{s_1}g_{T-s_1} \end{aligned} gT=fT+(1)×s1T,s1=fs1gTs1fT=gT+s1T,s1=fs1gTs1
于是就能求出 f S f_S fS 了。

这道题的总体思路是先求 S S S 形成的图是若干个出度为 0 0 0 的 scc 的方案数 g S g_S gS(用总的方案数减去 DAG 的方案数),再求 S S S 形成的图是一个出度为 0 0 0 的 scc 的方案数 f S f_S fS(用 g S g_S gS 减去多个 scc 的方案数)。

#include<bits/stdc++.h>

#define N 17
#define PN 33000

using namespace std;

namespace modular
{
	const int mod=1000000007;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int n,m,maxn,E1[PN],E2[PN][N];
int pow2[N*N],minid[PN];
int f[PN],g[PN];

void init()
{
	pow2[0]=1;
	for(int i=1;i<=m;i++)
		pow2[i]=add(pow2[i-1],pow2[i-1]);
	maxn=pow2[n]-1;
	for(int i=1;i<=maxn;i++)
	{
		if(i&1) minid[i]=1;
		else minid[i]=minid[i>>1]+1;
	}
}

int main()
{
	n=read(),m=read();
	if(m<n)
	{
		puts("0");
		return 0;
	}
	init();
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		int pu=pow2[u-1],pv=pow2[v-1];
		for(int S=maxn^pu^pv,now=S;;now=(now-1)&S)
		{
			E1[now^pu^pv]++;
			if(!now) break;
		}
		for(int S=maxn^pu,now=S;;now=(now-1)&S)
		{
			if((now>>(v-1))&1) continue;
			E2[now^pu][v]++;
			if(!now) break;
		}
	}
	g[0]=mod-1;
	for(int S=1;S<=maxn;S++)
	{
		g[S]=pow2[E1[S]];
		for(int T=(S-1)&S;T!=0;T=(T-1)&S)
		{
			int sum=0,now=T;
			while(now)
			{
				sum+=E2[S^T][minid[now]];
				now^=pow2[minid[now]-1];
			}
			g[S]=dec(g[S],mul(g[T],mul(pow2[E1[S^T]],pow2[sum])));
		}
	}
	for(int T=1;T<=maxn;T++)
	{
		f[T]=g[T];
		int p=pow2[minid[T]-1],S=T^p;
		if(!S) continue;
		for(int s1=(S-1)&S;;s1=(s1-1)&S)
		{
			f[T]=add(f[T],mul(f[s1^p],g[T^(s1^p)]));
			if(!s1) break;
		}
	}
	printf("%d\n",f[maxn]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值