聯賽模擬測試25 A. Adore 狀壓DP
阿新 • • 發佈:2020-10-29
題目描述
分析
看到 \(k \leq 10\) 和有關奇偶的問題就應該聯想到狀壓 \(DP\)
我們用狀態 \(0\) 表示表示到當前的點有偶數條路徑,用 \(1\) 表示到當前的點有奇數條路徑
對於每一層的點,我們儲存正向和反向時該點能到達的點的集合
然後分兩種情況轉移即可
時間複雜度 \(O(mk \times 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\n",ans); return 0; }