CF1672G Cross Xor
自己编的垃圾做法,感觉好麻烦啊/ll
约定:本文所有
显然,一个位置不会被操作
令
可以列出
但这个矩阵不一定满秩!
于是我们暴力跑线性基来求出这个矩阵的非自由元。
这里先给出一些有关
设
根据定义,我们有
对于固定的
对于固定的
分
打表可以发现这个方程一定是满秩的!
根据矩阵的结论可以得到任何一种填法都可以对应一组解。直接计算即可。
打表可以发现始终存在一组非自由元长这样(
n=6 m=7
1111111
1111110
1111110
1111110
1111110
1111110
分析什么样的
首先钦定所有自由元都为
你可以像我一样对着这一坨东西手算,其实花不了多久也能得出正确结论:
即每一行的异或和都相同。
当然你也可以直接分析操作性质猜出结论,然后回过头再来证明也是比较容易的。
枚举每一行的异或和,我们可以在每一行列出一个关于
显然这
打表可以发现始终存在一组非自由元长这样(
n=7 m=7
1111111
1111110
1111110
1111110
1111110
1111110
0000000
与上一种情况类似,我们可以得出结论:
即每一行的异或和都相同,每一列的异或和都相同。
又因为
枚举每一行每一列的异或和,我们可以在每一行每一列列出一个关于
此时就没那么简单了,这
我们考虑选一部分方程使得它们线性相关的条件。
因为每一个变量只会出现两个方程中,所以如果其中一个被选中了,那么另一个也必须被选中,否则就线性无关了。
因此我们考虑建立一张
每一个连通块对应一组线性相关的方程,设连通块个数为
至此,我们已经讨论完了所有情况。
时间复杂度
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define N 4005
#define MOD 998244353
#define pb push_back
#define pct __builtin_popcount
int n,m;char a[N][N];
void W(int &x,int y) {x+=y;if(x>=MOD) x-=MOD;}
int add(int x,int y) {x+=y;return x<MOD?x:x-MOD;}
int qPow(int x,int y)
{
int res=1;
for(;y;y/=2,x=1ll*x*x%MOD) if(y&1)
res=1ll*res*x%MOD;return res;
}
namespace Sub1
{
int t;
void slv()
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) t+=a[i][j]=='?';
printf("%d\n",qPow(2,t));
}
}
namespace Sub2
{
int t,fl,cnt[N],w[N];
void slv()
{
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
if(a[i][j]=='?') ++cnt[i];
else w[i]^=a[i][j]-48;
for(int i=1;i<=n;++i) if(cnt[i]) t+=cnt[i]-1;
for(int i=1;i<=n;++i) if(!cnt[i]) fl|=1<<w[i];
printf("%lld\n",1ll*qPow(2,t)*(2-pct(fl))%MOD);
}
}
namespace Sub3
{
int t,fl,cnt[N],w[N];
void slv()
{
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
if(a[i][j]=='?') ++cnt[j];
else w[j]^=a[i][j]-48;
for(int i=1;i<=m;++i) if(cnt[i]) t+=cnt[i]-1;
for(int i=1;i<=m;++i) if(!cnt[i]) fl|=1<<w[i];
printf("%lld\n",1ll*qPow(2,t)*(2-pct(fl))%MOD);
}
}
namespace Sub4
{
int t,fl,w[N];bool vs[N];vector<int> e[N];
int dfs(int u)
{
if(vs[u]) return 0;vs[u]=1;int res=w[u];
for(auto v:e[u]) res^=dfs(v);return res;
}
void slv()
{
t=-n-m;
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
if(a[i][j]=='?') ++t,e[i].pb(n+j),e[n+j].pb(i);
else w[i]^=a[i][j]-48,w[n+j]^=a[i][j]-48;
for(int i=1;i<=n+m;++i) if(!vs[i]) fl|=dfs(i),++t;
for(int i=1;i<=n+m;++i) vs[i]=0,w[i]^=1;
for(int i=1;i<=n+m;++i) if(!vs[i]) fl|=dfs(i)*2;
printf("%lld\n",1ll*qPow(2,t)*(2-pct(fl))%MOD);
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%s",a[i]+1);
if(!(n&1) && !(m&1)) Sub1::slv();
if(!(n&1) && m&1) Sub2::slv();
if(n&1 && !(m&1)) Sub3::slv();
if(n&1 && m&1) Sub4::slv();return 0;
}