P11714

可能更好的阅读体验

数有向图强连通子图,\(1\le n\le 15\)

反正写到我看得懂的程度,不保证所有人都能看懂。

Sol

下记 \(E(S,T)\) 为起点在 \(S\) 中且终点在 \(T\) 中的边数,\(lowbit(S)\)\(S\) 中最小的一位。

显然状压 dp,设 \(f_S\)\(S\) 的强连通子图个数。

考虑用 \(2^{E(S,S)}\) 减去不强连通的子图个数。

考虑对缩点后的零度 SCC 容斥,设 \(g_S\) 为将 \(S\) 中的点划分为 \(x\) 个 SCC 的方案数并带上容斥系数 \((-1)^{x-1}\)

即:\(g_S=\sum_{A_1,A_2,\dots,A_x}(-1)^{x-1}\prod_{i=1}^{x}f_{A_i}\),其中 \(A_1,A_2,\dots,A_x\)\(S\) 的一个划分(\(x\) 可以为 \(1\))。

有一个错误的想法是 \(g_S=f_S-\sum_{x\subsetneq S}f_xg_{S-x}\),因为一个划分方案会被计算多次。

变成枚举 \(lowbit(S)\) 被划分到的 SCC 即可解决,有 \(g_S=f_S-\sum_{x\subsetneq S,lowbit(x)=lowbit(S)}f_xg_{S-x}\)

然后求 \(f_S\),显然有 \(f_S=2^{Q(S,S)}-\sum_{x\subseteq S}g_x2^{Q(S,S-x)}\)

注意在计算 \(f_S\)\(g_S\) 中 的 \(f_S\) 不用考虑,因此是先 \(g_S\leftarrow-\sum_{x\subsetneq S,lowbit(x)=lowbit(S)}f_xg_{S-x}\),然后计算 \(f_S\),再 \(g_S\leftarrow f_S\)

接下来只要快速求 \(E(S,T)\) 就好了,为什么很多题解瓶颈都在这里啊,这个真难吗?/yun

考虑分 \(2\) 块,任意两个块间的状态数是 \(O(2^n)\) 的,因此可以使用 lowbit 递推预处理时间复杂度 \(O(2^n)\),单次查询时间复杂度 \(T(4)=O(1)\)

总时间复杂度即为枚举子集的 \(O(3^n)\)

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define repll(i,l,r) for(ll i=(l);i<=(r);i++)
#define perll(i,r,l) for(ll i=(r);i>=(l);i--)
#define pb push_back
#define ins insert
#define clr clear
using namespace std;
namespace ax_by_c{
typedef long long ll;
const ll mod=1e9+7;
const int N=20;
const int M=N*N;
const int S=(1<<15)+5;
const int PS=(1<<8)+5;
int lb(int x){
	return x&(-x);
}
int pn,pmsk,smsk,cnt[PS][PS][2][2];
void Init_cnt(){
	rep(x,0,1)rep(y,0,1){
		rep(s,0,pmsk){
			rep(i,1,pmsk)cnt[i][s][x][y]=cnt[i][lb(s)][x][y]+cnt[i][s^lb(s)][x][y];
		}
		rep(s,0,pmsk){
			rep(i,1,pmsk)cnt[s][i][x][y]=cnt[lb(s)][i][x][y]+cnt[s^lb(s)][i][x][y];
		}
	}
}
int Q(int S,int T){
	return cnt[S&pmsk][T&pmsk][0][0]+cnt[S>>pn][T&pmsk][1][0]+cnt[S&pmsk][T>>pn][0][1]+cnt[S>>pn][T>>pn][1][1];
}
int n,m,msk;
ll pw2[N*N],f[S],g[S];
void slv(int _csid,int _csi){
	scanf("%d %d",&n,&m);
	msk=(1<<n)-1,pn=(n+1)/2,pmsk=(1<<pn)-1,smsk=(1<<(n-pn))-1;
	rep(_,1,m){
		int u,v;
		scanf("%d %d",&u,&v);
		cnt[(u>pn)?(1<<(u-pn-1)):(1<<(u-1))][(v>pn)?(1<<(v-pn-1)):(1<<(v-1))][u>pn][v>pn]++;
	}
	Init_cnt();
	pw2[0]=1;
	rep(i,1,m)pw2[i]=pw2[i-1]*2%mod;
	rep(s,1,msk){
		f[s]=pw2[Q(s,s)];
		for(int x=(s-1)&s;x;x=(x-1)&s)if(lb(x)==lb(s)){
			g[s]=(g[s]-f[x]*g[s^x]%mod+mod)%mod;
		}
		for(int x=s;x;x=(x-1)&s){
			f[s]=(f[s]-g[x]*pw2[Q(s,s^x)]%mod+mod)%mod;
		}
		g[s]=(g[s]+f[s])%mod;
	}
	printf("%lld\n",f[msk]);
}
void main(){
	int T=1,csid=0;
//	scanf("%d",&csid);
//	scanf("%d",&T);
	rep(i,1,T)slv(csid,i);
}
}
int main(){
	string __name="";
	if(__name!=""){
		freopen((__name+".in").c_str(),"r",stdin);
		freopen((__name+".out").c_str(),"w",stdout);
	}
	ax_by_c::main();
	return 0;
}
posted @ 2025-05-30 16:30  ax_by_c  阅读(17)  评论(0)    收藏  举报