传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2560
Sol
正难则反 直接统计可行的状态不好统计 就反过来统计不可行的状态 再用所有状态减去不可行的状态
在算不可行状态的时候 固定一个定点 与这个定点联通的点为集合$st1$ 与这个定点不连通的点为集合$st2$
引入$f,g$ $g$表示随意连边可产生的方案数 $f$为连边联通的方案数
这样产生的不合法方案数$g_{st2}*f_{st1}$
而由于固定了一个定点 所以可以保证算出来的方案数不重不漏
题目同时涉及了一个枚举子集的方法=v=
Code
#include <bits/stdc++.h> using namespace std; const int fish=1000000007; int N; long long a[1000][1000],f[65550],g[65550]; int main() { scanf("%d",&N); for (int i=1;i<=N;i++) for (int j=1;j<=N;j++) scanf("%d",&a[i][j]); int ST=(1<<N)-1; for (int i=1;i<=ST;i++) { g[i]=1; for (int j=1;j<=N;j++) if (i&(1<<(j-1))) for (int k=j+1;k<=N;k++) if (i&(1<<k-1)) g[i]=g[i]*(a[j][k]+1)%fish; f[i]=g[i]; int zt=0; for (int j=N;j>=0;j--) if (i&(1<<j-1)) { zt=j; break; } zt=i^(1<<zt-1); for (int j=zt;j;j=zt&(j-1))//枚举所有子集的方法 f[i]=(f[i]-g[j]*f[i^j]*1ll%fish+fish)%fish; } printf("%lld",f[ST]%fish); return 0; }