操吴戈兮披犀甲
先给 EI 磕三个
上回书说到有一个
首先考虑用
这是二次型,考虑把
我们考虑对
于是我们就可以把
- 翻折
注意到
当然运算都在模意义下进行。
- 找主元+消元
取
那么考虑
那么这样一来,我们找到
为什么不直接换到第一行?如果换到第一行,那么第一列也要被换走,然后就寄了
下面还要用这个去消掉别的
这样一来,我们就能把矩阵中除了
这种情况相当于图是一个带有若干自环的链,那么直接 DP 即可。
然后我们发现复杂度的瓶颈在消元那一步,考虑我们依次施加若干个变换
考虑先做行,发现如果我们维护的是行的 bitset 那可以直接做;然后再做列,注意到这个是把第
这样总复杂度就是
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
return x*f;
}
const int N=45;
bitset<N>G[N];
int n,m;
ll f[2][2],g[2][2];
signed main(void){
#ifdef YUNQIAN
freopen("in.in","r",stdin);
#endif
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
G[u].flip(v),G[u].flip(u),G[v].flip(v);
}
for(int i=1;i<=n;i++){
// step 1
for(int j=i+1;j<=n;j++)if(G[i][j])G[j].flip(i),G[i][j]=0;
// step 2
int p=-1;
for(int j=i+1;j<=n;j++)if(G[j][i]!=0)p=j;
if(p==-1)continue;
swap(G[p],G[i+1]);
for(int j=i+1;j<=n;j++){
bool t=G[j][p];
G[j][p]=G[j][i+1],G[j][i+1]=t;
}
// step 3
bitset<N>f;f.reset();
for(int j=i+2;j<=n;j++)if(G[j][i])G[j]^=G[i+1],f[j]=1;
for(int j=i+1;j<=n;j++)if(G[j][i+1])G[j]^=f;
}
f[0][0]=1;
for(int i=1;i<=n;i++){
memset(g,0,sizeof(g));
for(int x=0;x<=1;x++)for(int y=0;y<=1;y++){
g[0][y]+=f[x][y];
if(x==0)g[1][y^G[i][i]]+=f[x][y];
else g[1][y^G[i][i]^G[i][i-1]]+=f[x][y];
}
for(int x=0;x<=1;x++)for(int y=0;y<=1;y++)f[x][y]=g[x][y];
}
ll ans=f[0][0];ans+=f[1][0];
cout<<ans<<endl;
return 0;
}