题解:AT_abc411_g [ABC411G] Count Cycles
更好的阅读体验
这是一个图上计数问题,数据范围很小,我们考虑进行状压 dp。
一个简单环原则上是不能经过重边的,因此我们要把二元环单独计数。
考虑大小
然而我们会发现至此还是错的。一个环从一个点出发可以顺时针走,也可以逆时针走。但是这样以来还是很好办,因为一个环会稳定地算成
那么我们模仿旅行商问题设计状态。令
至于如何转移,可以枚举下一个点
那么这道题就做完了,复杂度为
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 21
using namespace std;
const int MOD=998244353,inv2=MOD+1>>1;
int n,m,G[N][N],dp[1<<N][N],ans;
void add(int &x,int y){x+=y,x-=x>=MOD?MOD:0;}
main()
{
scanf("%lld%lld",&n,&m);
for(int i=1,u,v;i<=m;i++)
scanf("%lld%lld",&u,&v),G[u][v]++,G[v][u]++;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)add(ans,G[i][j]*(G[i][j]-1)%MOD);
for(int st=3;st<=n;st++)
{
memset(dp,0,sizeof(dp)),dp[1<<st-1][st]=1;
for(int S=1<<st-1;S<(1<<st);S++)
for(int i=1;i<=st;i++)if(S&(1<<i-1))
{
if(__builtin_popcountll(S)>2)add(ans,dp[S][i]*G[st][i]%MOD);
for(int j=1;j<=st;j++)if(!(S&(1<<j-1)))
add(dp[S|(1<<j-1)][j],dp[S][i]*G[i][j]%MOD);
}
}
ans=ans*inv2%MOD,printf("%lld\n",ans);
return 0;
}