非常经典的 DAG 计数,由于不是完全图,所以要进行子集 DP.
然后容斥一下发现可以写成 FST 的形式.
code:
#include <bits/stdc++.h>
#define N 23
#define ll long long
#define mod 998244353
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int inv2,n,m,mp[N][N],bin[N],size[1<<N];
int E[1<<N],dp[N][1<<N],g[N][1<<N];
inline int qpow(int x,int y)
{
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1)
tmp=(ll)tmp*x%mod;
return tmp;
}
inline int INV(int x) { return qpow(x,mod-2); }
void FWT(int *a,int len,int opt)
{
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j+=i<<1)
for(int k=0;k<i;++k)
{
int x=a[j+k],y=a[j+k+i];
a[j+k]=(ll)(x+y)%mod,a[j+k+i]=(ll)(x-y+mod)%mod;
if(opt==-1) a[j+k]=(ll)inv2*a[j+k]%mod,a[j+k+i]=(ll)inv2*a[j+k+i]%mod;
}
}
int main()
{
// setIO("input");
inv2=INV(2);
scanf("%d%d",&n,&m);
for(int i=1;i<=n+1;++i) bin[i]=1<<(i-1);
for(int i=1;i<=m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x][y]=mp[y][x]=1;
}
for(int S=1;S<bin[n+1];++S)
{
int fi;
for(int j=1;j<=n;++j)
if(S&bin[j]) { E[S]=E[S^bin[j]],fi=j; break; }
size[S]=size[S^bin[fi]]+1;
for(int j=1;j<=n;++j) if(mp[fi][j]&&(S&bin[j])) ++E[S];
}
for(int i=1;i<bin[n+1];++i)
{
int d=(size[i]%2)==0?(mod-1):1;
g[size[i]][i]=(ll)d*INV(qpow(2,E[i]))%mod;
}
dp[0][0]=1;
FWT(dp[0],bin[n+1],1);
for(int i=1;i<=n;++i) FWT(g[i],bin[n+1],1);
for(int sz=1;sz<=n;++sz)
{
for(int i=1;i<=sz;++i)
for(int s=0;s<bin[n+1];++s)
(dp[sz][s]+=(ll)g[i][s]*dp[sz-i][s]%mod)%=mod;
}
FWT(dp[n],bin[n+1],-1);
printf("%d\n",(ll)dp[n][bin[n+1]-1]*qpow(2,E[bin[n+1]-1])%mod*INV(qpow(3,E[bin[n+1]-1]))%mod);
return 0;
}