矩阵 状压dp

来源:互联网 发布:社交网络 评论音轨 编辑:程序博客网 时间:2024/06/16 09:22

题意:

有一个n*m的01矩阵,矩阵中k个格子的数已经确定,你需要求出有多少种方案使得矩阵每行每列的异或和均为1。对998244353取模。

n<=10^5,m<=2*10^5,k<=2*10^6


分析:

细节好多啊,做了一晚上才做出来。


首先如果n和m奇偶性不同则结果必然为0.

若存在一列全为空,那么在其他数全部确定后,这一列恰好有一种方案使得每行的异或和恰好为1,并且只要其他列的异或和为1,则这一列的异或和也为1。然后对于那些没有填满的列,设有x个空格子,则方案数为2^(x-1)。


注意到所有数据点都满足k<=10m,我们可以找到空格子数最多的那一列,设已经确定的格子数为p,则有p<=10.

对于除了这p行以外的其他行,当除了这一列以外的数全部确定后,可以通过这一列来使其异或和均为1.

对于除了这一列以外的其他列,若这列除了这p行外有至少一个空格子,则可以通过提出这个空格子来保证这一列异或和必然为1.

对于一行特殊行,若这种列中有x列满足这一行为空,则这一行的总取值为0或1的方案都要乘上2^(x-1)。

那么现在需要决策的就只有这p行和那些除这p行以外的格子均已被决定了的列。

我们设f[i,j,k,l]表示现在决策到第i列的第j行,当前列异或和为k,这p行的异或和为l(l为p位二进制数)时的方案,那么只要枚举该位放什么然后转移即可。


代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<vector>using namespace std;typedef long long LL;const int N=200005;const int M=25;const int MOD=998244353;int n,m,c1,r1,r[M],c[M],za[M][M],bin[M],f[M][M][2][1105],k,cnt[N],ty[M],tyc[M],val[N];bool tag[N],vis[N];vector<int> bel[N];struct data{int x,y,z;}a[2000005];int read(){int x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}int ksm(int x,int y){if (y<1) return 1;int ans=1;while (y){if (y&1) ans=(LL)ans*x%MOD;x=(LL)x*x%MOD;y>>=1;}return ans;}int get(int x){return lower_bound(r+1,r+r1+1,x)-r;}void solve(int pos){int ans=1;for (int i=1;i<=m;i++)if (i!=pos) ans=(LL)ans*ksm(2,max(n-cnt[i]-1,0))%MOD;printf("%d",ans);}int dp(int pos){bin[0]=1;for (int i=1;i<=r1;i++) bin[i]=bin[i-1]*2;for (int s=0;s<bin[r1];s++){f[0][r1][1][s]=1;for (int i=1;i<=r1;i++)if (!cnt[r[i]]){if (((s>>(i-1))&1)!=ty[i]){f[0][r1][1][s]=0;break;}}else f[0][r1][1][s]=(LL)f[0][r1][1][s]*ksm(2,cnt[r[i]]-1)%MOD;}for (int i=0;i<=c1;i++)for (int j=1;j<=r1;j++)for (int k=0;k<=1;k++)for (int l=0;l<bin[r1];l++)if (f[i][j][k][l]){int i1=i,j1=j+1,k1=k,l1=l;if (j1>r1){if (k==tyc[i]||i==c1) continue;i1++;j1=1;k1=0;}if (za[j1][i1]>-1){k1^=za[j1][i1];l1^=za[j1][i1]<<(j1-1);(f[i1][j1][k1][l1]+=f[i][j][k][l])%=MOD;}else{(f[i1][j1][k1][l1]+=f[i][j][k][l])%=MOD;k1^=1;l1=l^bin[j1-1];(f[i1][j1][k1][l1]+=f[i][j][k][l])%=MOD;}}return f[c1][r1][tyc[c1]^1][bin[r1]-1];}int main(){n=read();m=read();k=read();swap(n,m);if (n%2!=m%2){putchar('0');return 0;}for (int i=1;i<=k;i++){a[i].x=read();a[i].y=read();a[i].z=read();swap(a[i].x,a[i].y);cnt[a[i].y]++;bel[a[i].y].push_back(i);val[a[i].y]^=a[i].z;}for (int i=1;i<=m;i++) if (cnt[i]==n&&!val[i]){putchar('0');return 0;}int mn=n,pos=0;for (int i=1;i<=m;i++)if (cnt[i]<mn) mn=cnt[i],pos=i;if (!mn){solve(pos);return 0;}printf("%d",ksm(2,n*m-k-n-m+1));/*memset(cnt,0,sizeof(cnt));int ans=1;for (vector<int>::iterator it=bel[pos].begin();it!=bel[pos].end();it++) tag[a[*it].x]=1,r[++r1]=a[*it].x,ty[r1]=a[*it].z;sort(r+1,r+r1+1);for (int i=1;i<=m;i++)if (i!=pos){int s=0,w;for (vector<int>::iterator it=bel[i].begin();it!=bel[i].end();it++) if (tag[a[*it].x]) s++,vis[a[*it].x]=1;if (w=n-r1-bel[i].size()+s){ans=(LL)ans*ksm(2,w-1)%MOD;for  (int j=1;j<=r1;j++) if (!vis[r[j]]) cnt[r[j]]++; else vis[r[j]]=0;  for (vector<int>::iterator it=bel[i].begin();it!=bel[i].end();it++) if (tag[a[*it].x]) ty[get(a[*it].x)]^=a[*it].z;}else{c[++c1]=i;for (int j=1;j<=r1;j++) za[j][c1]=-1;for (vector<int>::iterator it=bel[i].begin();it!=bel[i].end();it++) if (tag[a[*it].x]) za[get(a[*it].x)][c1]=a[*it].z;}}for (int i=1;i<=c1;i++)for (vector<int>::iterator it=bel[c[i]].begin();it!=bel[c[i]].end();it++)if (!tag[a[*it].x]) tyc[i]^=a[*it].z;ans=(LL)ans*dp(pos)%MOD;printf("%d",ans);*/return 0;}