[HNOI/AHOI2018] 毒瘤
Larunatrecy · · 题解
在一些科技普及之后这个题好像就没什么意义了?
因为
我们可以发现:
-
删一度点相当于把某个连通子集挂在另一个点上,且之后这个子集和别的点没有任何关系
-
缩二度点相当于把两个连通子集串起来,方案数相乘再求和即可
-
叠合重边,缩二度点的过程有可能产生重边,此时相当于并起来,方案数直接相乘
对于每条边
最后剩下的图中不超过
复杂度
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+7;
map<int,int> mp[N];
int f[N][2][2],U[N],V[N];
int w[N][2],deg[N];
int n,m;
queue<int> q;
bool del[N];
inline int F(int e,int x,int c,int y,int d)
{
if(x==U[e])return f[e][c][d];
return f[e][d][c];
}
const int mod = 998244353;
int tmp[2][2];
int id[N],tot=0;
int seq[N],Eu[N],Ev[N],Ew[N][2][2];
int state[N];
bool ban[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)w[i][0]=w[i][1]=1;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&U[i],&V[i]);
if(mp[U[i]][V[i]])continue;
mp[U[i]][V[i]]=i;
mp[V[i]][U[i]]=i;
f[i][0][0]=f[i][1][0]=f[i][0][1]=1;
deg[U[i]]++;deg[V[i]]++;
}
for(int i=1;i<=n;i++)if(deg[i]<=2)q.push(i);
while(!q.empty())
{
int x=q.front();
q.pop();
if(del[x])continue;
if(deg[x]==0)continue;
del[x]=1;
if(deg[x]==1)
{
auto A=(*mp[x].begin());mp[x].erase(mp[x].begin());
int y=A.first,e=A.second;
deg[y]--;mp[y].erase(x);deg[x]=0;
ban[e]=1;
for(int c=0;c<=1;c++)
{
int v=0;
for(int d=0;d<=1;d++)
v=(v+1ll*w[x][d]*F(e,x,d,y,c)%mod)%mod;
w[y][c]=1ll*w[y][c]*v%mod;
}
if(deg[y]<=2)q.push(y);
continue;
}
auto A=(*mp[x].begin());mp[x].erase(mp[x].begin());
auto B=(*mp[x].begin());mp[x].erase(mp[x].begin());
int yA=A.first,eA=A.second;
int yB=B.first,eB=B.second;
int eC=mp[yA][yB];
deg[x]=0;
mp[yA].erase(x);mp[yB].erase(x);
for(int a=0;a<=1;a++)//yA
for(int b=0;b<=1;b++)//yB
{
tmp[a][b]=0;
for(int c=0;c<=1;c++)
tmp[a][b]=(tmp[a][b]+1ll*F(eA,yA,a,x,c)*F(eB,yB,b,x,c)%mod*w[x][c]%mod)%mod;
}
U[eA]=yA;V[eA]=yB;
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
f[eA][a][b]=tmp[a][b];
mp[yA][yB]=mp[yB][yA]=eA;
if(eC)
{
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
f[eA][a][b]=1ll*f[eA][a][b]*F(eC,yA,a,yB,b)%mod;
deg[yA]--;deg[yB]--;
if(deg[yA]<=2)q.push(yA);
if(deg[yB]<=2)q.push(yB);
ban[eC]=1;
}
}
for(int x=1;x<=n;x++)if(!del[x])
{
seq[++tot]=x;
id[x]=tot;
}
int C=0;
for(int x=1;x<=n;x++)if(!del[x])
{
for(auto U:mp[x])
{
int y=U.first,e=U.second;
if(x<y)
{
++C;
Eu[C]=id[x];
Ev[C]=id[y];
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
Ew[C][a][b]=F(e,x,a,y,b);
}
}
}
int ans=0;
for(int S=0;S<(1<<tot);S++)
{
int res=1;
for(int i=1;i<=tot;i++)
{
state[i]=((S>>(i-1))&1);
res=1ll*res*w[seq[i]][state[i]]%mod;
}
for(int i=1;i<=C;i++)
res=1ll*res*Ew[i][state[Eu[i]]][state[Ev[i]]]%mod;
ans=(ans+res)%mod;
}
cout<<ans;
return 0;
}