容斥的做法,35pts。
#include<iostream>
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<vector>
#define N 100005
#define M 55
#define fi first
#define se second
#define mo 998244353
#define int long long
using namespace std;
inline int read(){
int x=0,f=0; char ch=getchar();
while(!isdigit(ch)) f|=(ch==45),ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void red(int &x){x>=mo?x-=mo:0;}
struct edge{
int b,n;
}e[N*2];
int ans,n,m,ff[N],h[N],tot,flag[N],sze[N],ne[N],f[N][2],pre[M][M][2][2],g[N][2],id[N];
vector <pair<int,int> > mp;
vector <int> G[N];
inline void charu(int a,int b){
e[++tot].b=b,e[tot].n=h[a],h[a]=tot;
}
int find(int x){
return x==ff[x]?x:(ff[x]=find(ff[x]));
}
pair<int,int> getPre(int u,int fa,int S,int T,int z){
if(u==T) return {(z==0),(z==1)};
pair<int,int> res;
res.fi=res.se=1;
for(int i=h[u];i;i=e[i].n){
int v=e[i].b;
if(v==fa) continue;
if(u==S){
if(ne[v]==T){
pair<int,int> tmp=getPre(v,u,S,T,z);
(res.fi*=(tmp.fi+tmp.se)%mo)%=mo;
(res.se*=tmp.fi)%=mo;
}
}
else{
if(ne[v]==T){
pair<int,int> tmp=getPre(v,u,S,T,z);
(res.fi*=(tmp.fi+tmp.se)%mo)%=mo;
(res.se*=tmp.fi)%=mo;
}
else{
(res.fi*=(f[v][0]+f[v][1])%mo)%=mo;
(res.se*=f[v][0])%=mo;
}
}
}
return res;
}
void dealFirst(int u,int fa){
sze[u]=flag[u];f[u][0]=f[u][1]=g[u][0]=g[u][1]=1;
for(int i=h[u];i;i=e[i].n){
int v=e[i].b;
if(v==fa) continue;
dealFirst(v,u);
(f[u][0]*=(f[v][0]+f[v][1])%mo)%=mo;
(f[u][1]*=f[v][0])%=mo;
if(sze[u] && flag[v]) flag[u]=1;
sze[u]|=sze[v];
}
if(flag[u]) ne[u]=u;
for(int i=h[u];i;i=e[i].n){
int v=e[i].b;
if(v==fa) continue;
if(flag[u] && ne[v]) G[u].push_back(ne[v]);
if(!flag[u] && ne[v]) ne[u]=ne[v];
}
if(!flag[u]) return;
id[u]=++id[0];
for(int i=h[u];i;i=e[i].n){
int v=e[i].b;
if(v==fa) continue;
if(!ne[v]){
(g[u][0]*=(f[v][0]+f[v][1])%mo)%=mo;
(g[u][1]*=f[v][0])%=mo;
}
else{
pair<int,int> tmp=getPre(u,fa,u,ne[v],0);
pre[id[u]][id[ne[v]]][0][0]=tmp.fi;
pre[id[u]][id[ne[v]]][1][0]=tmp.se;
tmp=getPre(u,fa,u,ne[v],1);
pre[id[u]][id[ne[v]]][0][1]=tmp.fi;
pre[id[u]][id[ne[v]]][1][1]=tmp.se;
}
}
}
pair<int,int> solve(int u){
pair<int,int> res;
res.fi=g[u][0],res.se=g[u][1];
if(flag[u]) res.fi=0;
for(int v:G[u]){
pair<int,int> tmp=solve(v);
(res.fi*=(tmp.fi*pre[id[u]][id[v]][0][0]%mo+tmp.se*pre[id[u]][id[v]][0][1]%mo)%mo)%=mo;
(res.se*=(tmp.fi*pre[id[u]][id[v]][1][0]%mo+tmp.se*pre[id[u]][id[v]][1][1]%mo)%mo)%=mo;
}
return res;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;++i) ff[i]=i;
for(int i=1;i<=m;++i){
int x=read(),y=read();
if(find(x)==find(y)){
mp.push_back({x,y});
flag[x]=flag[y]=1;
fprintf(stderr,"%d %d\n",x,y);
}
else{
charu(x,y),charu(y,x);
ff[ff[x]]=ff[y];
}
}
flag[1]=1;
dealFirst(1,0);
m-=(n-1);
memset(flag,0,sizeof(flag));
for(int s=0;s<(1<<m);++s){
for(int i=0;i<m;++i) if((1<<i)&s)
flag[mp[i].fi]=flag[mp[i].se]=1;
int k=(__builtin_popcount(s)%2?mo-1:1);
pair<int,int> tmp=solve(1);
int t=tmp.fi+tmp.se;red(t);
red(ans+=k*t%mo);
for(int i=0;i<m;++i) if((1<<i)&s)
flag[mp[i].fi]=flag[mp[i].se]=0;
}
cout<<ans;
return 0;
}