题目描述
分析
看到 (k leq 10) 和有关奇偶的问题就应该联想到状压 (DP)
我们用状态 (0) 表示表示到当前的点有偶数条路径,用 (1) 表示到当前的点有奇数条路径
对于每一层的点,我们存储正向和反向时该点能到达的点的集合
然后分两种情况转移即可
时间复杂度 (O(mk imes 2^k))
代码
#include<cstdio>
#include<vector>
#include<cstring>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e4+5,maxk=12;
const int mod=998244353;
int m,k,f[maxn][1<<maxk],a[maxk],b[maxk],ans,mmax;
bool vis[maxk];
int main(){
m=read(),k=read();
rg int aa,now=0;
for(rg int i=1;i<=k;i++){
aa=read();
now|=(aa<<(i-1));
}
mmax=(1<<k)-1;
f[1][now]=1;
for(rg int i=2;i<m-1;i++){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(rg int j=1;j<=k;j++){
for(rg int o=1;o<=k;o++){
aa=read();
a[j]|=(aa<<(o-1));
b[o]|=(aa<<(j-1));
}
}
for(rg int j=0;j<=mmax;j++){
if(f[i-1][j]){
rg int now1=0,now2=0;
for(rg int o=1;o<=k;o++){
if(j&(1<<(o-1))){
now1^=a[o];
now2^=b[o];
}
}
f[i][now1]+=f[i-1][j];
if(f[i][now1]>=mod) f[i][now1]-=mod;
f[i][now2]+=f[i-1][j];
if(f[i][now2]>=mod) f[i][now2]-=mod;
}
}
}
for(rg int i=1;i<=k;i++){
vis[i]=read();
}
for(rg int i=0;i<=mmax;i++){
if(f[m-2][i]){
rg int cnt=0;
for(rg int j=1;j<=k;j++){
if(vis[j] && i&(1<<(j-1))) cnt++;
}
if(cnt&1) continue;
ans+=f[m-2][i];
if(ans>=mod) ans-=mod;
}
}
printf("%d
",ans);
return 0;
}