先给 EI 磕三个
首先考虑用 \(n\) 个变量 \(x_1,x_2,\cdots,x_n\in\{0,1\}\) 表示第 \(i\) 个点选不选,那么导出子图的边数的奇偶性就是
这是二次型,考虑把 \(f(v)\) 写成 \(v^\textsf{T}Av\) 的形式,其中 \(v\) 是 \(x_1,\cdots,x_n\) 的列向量,\(A_{i,j}\) 是上面这个多项式中 \(x_ix_j\) 项的系数。我们需要求出所有列向量 \(v\in\mathbb F_2^n\) 的 \(f(v)\) 之和。
我们考虑对 \(A\) 做一些变换来简化问题。考虑取矩阵 \(Q\),使得当 \(v\) 取遍 \(\mathbb F_2^n\) 的时候,\(Qv\) 也取遍 \(\mathbb F_{2}^n\)。那么就有
于是我们就可以把 \(A\) 变成 \(Q^{\mathsf T}AQ\)。这里直接给出这三种变换:
- 翻折
注意到 \(x_ix_j\) 的系数与 \(x_jx_i\) 的系数本质没有区别,因此我们可以对每个 \(i=2,\cdots,n\),令 \(A_{i,1}\leftarrow A_{i,1}+A_{1,i},A_{1,i}\leftarrow 0\)。容易发现这不会影响结果。这样一来,我们就把第一行除了 \(A_{1,1}\) 以外的数都变成了 \(0\)。如下:
当然运算都在模意义下进行。
- 找主元+消元
取 \(Q\) 为交换 \(x_i,x_j\) 对应的变换,即 \(Q_{k,k}=1(k\neq i,k\neq j),Q_{i,j}=Q_{j,i}=1\)。
那么考虑 \(Q^{\mathsf T}AQ\) 是啥,发现就是先交换 \(i,j\) 两行,再交换 \(i,j\) 两列。这样就实现了交换两行。
那么这样一来,我们找到 \(i\ge 2\) 使得 \(A_{i,1}\neq 1\),然后就可以把 \(A_{i,1}\) 交换到 \(A_{2,1}\) 的位置。如果不存在这样的 \(i\),我们的目标就已经达成了,可以直接对第 \(2\) 行开始重复这个过程。
为什么不直接换到第一行?如果换到第一行,那么第一列也要被换走,然后就寄了
下面还要用这个去消掉别的 \(A_{i,1}\),其中 \(i\ge 3\)。假设要消掉第 \(j\) 行,方法是:取 \(Q\) 为 \(x_j\leftarrow x_j+x_i\) 对应的变换,即 \(Q_{i,i}=1\)(\(1\le i\le n\)),以及 \(Q_{i,j}=1\)。那么 \(Q^{\mathsf T}AQ\) 是啥呢,发现造成的影响就是,先把所有 \(A_{j,k}\leftarrow A_{j,k}+A_{i,k}\),然后再把所有 \(A_{k,j}\leftarrow A_{k,j}+A_{k,i}\)。
这样一来,我们就能把矩阵中除了 \(A_{1,1},A_{2,1}\) 之外,第一行第一列的位置都消成 \(0\)。于是考虑一直这样做下去,就能在 \(O(n^3)\) 的时间内把矩阵变成只有 \(A_{i,i},A_{i,i-1}\) 非零的情况。
这种情况相当于图是一个带有若干自环的链,那么直接 DP 即可。
然后我们发现复杂度的瓶颈在消元那一步,考虑我们依次施加若干个变换 \(Q_1,Q_2,\cdots,Q_k\),那么原本的 \(A\) 就变成 \(Q_k^{\mathsf T}Q_{k-1}^{\mathsf T}\cdots Q_1^{\mathsf T}AQ_1\cdots Q_k=(\prod_{i=1}^k Q_i)^{\mathsf T}A(\prod_{i=1}^k Q_i)\),于是这个等价于一起做。
考虑先做行,发现如果我们维护的是行的 bitset 那可以直接做;然后再做列,注意到这个是把第 \(i\) 列异或到后面的某些列上面,考虑算出来这些列的 bitset,然后把对第 \(i\) 列上的每个 \(1\),就把这一行异或上这个 bitset。
这样总复杂度就是 \(O(\frac{n^3}{w})\)。
#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 mod=998244353;
int ksm(int x,int y,int p=mod){
int ans=1;
for(int i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
return ans%p;
}
int inv(int x,int p=mod){return ksm(x,p-2,p)%p;}
mt19937 rnd(time(0));
int randint(int l,int r){return rnd()%(r-l+1)+l;}
void add(int &x,int v){x+=v;if(x>=mod)x-=mod;}
void Mod(int &x){if(x>=mod)x-=mod;}
const int N=1005;
bitset<N>G[N];
int n,m,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);
}
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++){
add(g[0][y],f[x][y]);
if(x==0)add(g[1][y],f[x][y^G[i][i]]);
else add(g[1][y],f[x][y^G[i][i]^G[i][i-1]]);
}
for(int x=0;x<=1;x++)for(int y=0;y<=1;y++)f[x][y]=g[x][y];
}
int ans=f[0][0];add(ans,f[1][0]);
cout<<ans<<endl;
return 0;
}
- Universal Stage 6555 Good Setsuniversal stage 6555 good universal northern stage good universal stage the 2nd universal qingdao stage the universal contest nanjing stage universal binjiang stage the universal okayama stage the universal shenyang stage the universal shaanxi stage 6735 universal stage hefei the