http://cplusoj.com/d/senior/p/SS231024B?tid=653748c7611b23c4594b05ab
要么是环,要么是链,都可以有两个方向
链的话可以缩成点一起统计
长为2的链如果成二元环不应该乘2,那么考虑容斥
g ( i ) g(i) g(i) 表示至少有 i i i 个二元环不被算错的方案数, ∑ i = 0 k g ( i ) ( − 1 ) k − i \sum_{i=0}^kg(i)(-1)^{k-i} ∑i=0kg(i)(−1)k−i
g ( i ) = ( k i ) ( z + i ) ! 2 i g(i)=\binom k i(z+i)!2^i g(i)=(ik)(z+i)!2i
#include<bits/stdc++.h>
using namespace std;
#define int long long
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^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 500010
//#define M
#define mo 998244353
int pw(int a, int b) {
int ans=1;
while(b) {
if(b&1) ans*=a;
a*=a; b>>=1;
ans%=mo; a%=mo;
}
return ans;
}
int fac[N], inv[N], ifac[N];
void init(int n) {
int i;
for(i=fac[0]=1; i<=n; ++i) fac[i]=fac[i-1]*i%mo;
ifac[n]=pw(fac[n], mo-2);
for(i=n-1; i>=0; --i) ifac[i]=ifac[i+1]*(i+1)%mo;
for(i=1; i<=n; ++i) inv[i]=ifac[i]*fac[i-1]%mo;
}
int C(int n, int m) {
if(m>n) return 0;
return fac[n]*ifac[m]%mo*ifac[n-m]%mo;
}
void Add(int &a, int b) {
a+=b; if(a>=mo || a<=-mo) a%=mo;
if(a<0) a+=mo;
}
void Mul(int &a, int b) {
a*=b; if(a>=mo || a<=-mo) a%=mo;
if(a<0) a+=mo;
}
void Mod(int &a) {
if(a>=mo || a<=-mo) a%=mo;
if(a<0) a+=mo;
}
const int iv2=pw(2, mo-2);
int n, m, i, j, k, T, f[N], c[N], x, y;
int ans, sum, w[N], h[N], z;
map<pair<int, int>, int>mp;
int fa(int x) {
if(f[x]==x) return x;
return f[x]=fa(f[x]);
}
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
freopen("per.in", "r", stdin);
freopen("per.out", "w", stdout);
// T=read();
// while(T--) {
//
// }
n=read(); m=read(); init(n); ans=1;
for(i=1; i<=n; ++i) f[i]=i, w[i]=0;
for(i=1; i<=m; ++i) {
x=read(); y=read();
if(mp[{x, y}]) continue;
mp[{x, y}]=mp[{y, x}]=1;
// if(fa(x)==fa(y)) return printf("0"), 0;
if(fa(x)!=fa(y)) w[fa(y)]+=w[fa(x)];
f[fa(x)]=fa(y); w[fa(y)]++;
++c[x]; ++c[y];
if(c[x]>2 || c[y]>2) return printf("0"), 0;
}
for(i=1; i<=n; ++i) h[fa(i)]++;
for(i=1, k=0; i<=n; ++i)
if(fa(i)==i) {
if(!w[i]) ++z; //单点
else if(h[i]==1) continue; //自环
else if(h[i]==w[i]) Mul(ans, 2); //环
else if(h[i]==2) ++k; //双点链
else ++z, Mul(ans, 2); //正常链
}
// printf("%lld %lld | %lld\n", z, k, ans);
sum=0;
for(i=0; i<=k; ++i) {
if((k-i)&1) Add(sum, -C(k, i)*fac[i+z]%mo*pw(2, i)%mo);
else Add(sum, C(k, i)*fac[i+z]%mo*pw(2, i)%mo);
}
printf("%lld", ans*sum%mo);
return 0;
}