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;
}

浙公网安备 33010602011771号