联赛模拟测试25 A. Adore 状压DP

题目描述


分析

看到 (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;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13895701.html