解题思路:
首先如果图是一棵树,那么:
如果多了几条非树边,可以暴力枚举这几条边端点的状态,即强制选A不选B或强制不选A,所以得到了 的算法,可过75分。
考虑把有非树边的点当做关键点建虚树,那么对于虚树上的一条边,它的转移系数其实是不变的,即
如果我们求出了每条边的转移系数,那么最后就可以向暴力中枚举关键点状态来确定初始值dp即可,求法如下。
对于一条虚树边
将原树中的路径提出来
从节点
向上跳并暴力转移系数,若遇到分叉则额外转移上分叉处的系数
如果遇到一个新的关键点就重置系数。
这样复杂度是
的,可以在建虚树的同时处理。
所以复杂度为 为虚树大小。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=100010,mod=998244353;
int n,m,cnt,idx,eu[N],ev[N],dfn[N],vis[N],size[N],mark[N],fg[N][2];
vector<int>e[N];
ll g[N][2],f[N][2],ans;
struct data
{
ll x,y;
data(ll _x=0,ll _y=0):x(_x),y(_y){}
inline data operator + (const data b){return data((x+b.x)%mod,(y+b.y)%mod);}
inline data operator * (const int b){return data(x*b%mod,y*b%mod);}
}k[N][2],f0[N],f1[N];
int tot,first[N],nxt[N],to[N];
void dfs(int u,int fa)
{
dfn[u]=++idx;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];if(v==fa)continue;
if(dfn[v]&&dfn[v]<dfn[u])mark[u]=mark[v]=1,eu[++cnt]=u,ev[cnt]=v;
if(!dfn[v])dfs(v,u),size[u]+=size[v];
}
mark[u]|=(size[u]>=2),size[u]=mark[u]?1:size[u];
}
void add(int x,int y,data a,data b)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y,f0[tot]=a,f1[tot]=b;
}
int Vt(int u)
{
g[u][0]=g[u][1]=1,vis[u]=1;
int pos=0;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];if(vis[v])continue;
int w=Vt(v);
if(!w)g[u][0]=g[u][0]*(g[v][0]+g[v][1])%mod,g[u][1]=g[u][1]*g[v][0]%mod;
else
{
if(mark[u])add(u,w,k[v][0]+k[v][1],k[v][0]);
else k[u][0]=k[v][0]+k[v][1],k[u][1]=k[v][0],pos=w;
}
}
if(mark[u])k[u][0]=data(1,0),k[u][1]=data(0,1),pos=u;
else k[u][0]=k[u][0]*g[u][0],k[u][1]=k[u][1]*g[u][1];
return pos;
}
void dp(int u)
{
f[u][0]=fg[u][1]?0:g[u][0];
f[u][1]=fg[u][0]?0:g[u][1];
for(int e=first[u];e;e=nxt[e])
{
int v=to[e];dp(v);
f[u][0]=f[u][0]*(f0[e].x*f[v][0]%mod+f0[e].y*f[v][1]%mod)%mod;
f[u][1]=f[u][1]*(f1[e].x*f[v][0]%mod+f1[e].y*f[v][1]%mod)%mod;
}
}
int main()
{
//freopen("lx.in","r",stdin);
int x,y;
n=getint(),m=getint();
while(m--)x=getint(),y=getint(),e[x].pb(y),e[y].pb(x);
dfs(1,0),mark[1]=1,Vt(1);
for(int s=0;s<(1<<cnt);s++)
{
for(int i=1;i<=cnt;i++)
if(s&(1<<i-1))fg[eu[i]][1]=fg[ev[i]][0]=1;
else fg[eu[i]][0]=1;
dp(1),ans=(ans+f[1][1]+f[1][0])%mod;
for(int i=1;i<=cnt;i++)
if(s&(1<<i-1))fg[eu[i]][1]=fg[ev[i]][0]=0;
else fg[eu[i]][0]=0;
}
cout<<ans<<'\n';
}