题目大意
给定一个
n
×
m
n \times m
n×m 的 01 矩阵
A
0
A_0
A0。定义一次操作为将这个矩形每个元素求异或前缀和,即
A
k
[
i
,
j
]
=
(
∑
u
=
1
i
∑
v
=
1
j
A
k
−
1
[
u
,
v
]
)
m
o
d
2
A_k[i,j]=(\sum_{u=1}^i\sum_{v=1}^j A_{k-1}[u,v]) \bmod 2
Ak[i,j]=(∑u=1i∑v=1jAk−1[u,v])mod2。
求一个最小的正整数
k
k
k,使得
A
0
=
A
k
A_0=A_k
A0=Ak。
n × m ≤ 1 0 6 n\times m \leq 10^6 n×m≤106
\\
\\
\\
题解
首先,可以发现答案一定是
2
2
2 的幂。
可以这么说明这个结论,设
k
i
,
j
k_{i,j}
ki,j 表示左上角为
(
1
,
1
)
(1,1)
(1,1) 右下角为
(
i
,
j
)
(i,j)
(i,j) 的子矩形的答案,那么
k
i
,
j
k_{i,j}
ki,j 至少为
l
c
m
(
k
i
−
1
,
j
,
k
i
,
j
−
1
)
lcm(k_{i-1,j},k_{i,j-1})
lcm(ki−1,j,ki,j−1),如果这
l
c
m
lcm
lcm 轮过后
(
i
,
j
)
(i,j)
(i,j) 的元素没变,那么
k
i
,
j
k_{i,j}
ki,j 就等于这个,否则还要再来
l
c
m
lcm
lcm 轮把它变回来,即
k
i
,
j
=
l
c
m
⋅
2
k_{i,j}=lcm \cdot 2
ki,j=lcm⋅2。而又因为
k
1
,
1
=
1
k_{1,1}=1
k1,1=1,因此可以归纳证明任意
k
i
,
j
k_{i,j}
ki,j 一定是
2
2
2 的幂。
然后想一个问题,如果经过
k
k
k 轮操作,那么一个格子
(
x
,
y
)
(x,y)
(x,y) 对其右下的一个格子
(
x
+
Δ
x
,
y
+
Δ
y
)
(x+\Delta x,y+\Delta y)
(x+Δx,y+Δy) 的贡献是多少?
这等价于一个棋子从
(
x
,
y
)
(x,y)
(x,y) 开始,每次跳到其右下方的一个位置(包括自己本身),跳
k
k
k 步跳到
(
x
+
Δ
x
,
y
+
Δ
y
)
(x+\Delta x,y+\Delta y)
(x+Δx,y+Δy),的方案数是多少。
这显然是
(
Δ
x
+
k
−
1
k
−
1
)
⋅
(
Δ
y
+
k
−
1
k
−
1
)
\binom{\Delta x+k-1}{k-1} \cdot \binom{\Delta y+k-1}{k-1}
(k−1Δx+k−1)⋅(k−1Δy+k−1)。
而根据 Lucas 定理,当
k
k
k 为
2
2
2 的幂时,只有当
Δ
x
\Delta x
Δx 和
Δ
y
\Delta y
Δy 都是
k
k
k 的倍数的时候,这个式子才
m
o
d
2
=
1
\bmod~2=1
mod 2=1。
于是我们就可以
k
=
1
,
2
,
4
,
8
,
⋯
k=1,2,4,8,\cdots
k=1,2,4,8,⋯ 这样枚举答案,每次枚举中,每个位置只考虑
Δ
x
\Delta x
Δx 和
Δ
y
\Delta y
Δy 是
k
k
k 倍数的位置的贡献,可以
O
(
n
m
)
O(nm)
O(nm) 得出最终矩阵并判断。(看代码)
同时这样也说明答案不会很大,最多判断
log
n
m
\log nm
lognm 次。
代码
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
int n,m;
bool a[maxn];
inline int id(int i,int j) {return (i-1)*m+j;}
void ReadBit(bool &data)
{
char ch=getchar();
while (ch!='0' && ch!='1') ch=getchar();
data=(ch=='1');
}
bool b[maxn];
bool check(int k)
{
fo(i,1,n)
fo(j,1,m)
{
b[id(i,j)]=a[id(i,j)];
if (i>k) b[id(i,j)]^=b[id(i-k,j)];
if (j>k) b[id(i,j)]^=b[id(i,j-k)];
if (i>k && j>k) b[id(i,j)]^=b[id(i-k,j-k)];
if (b[id(i,j)]!=a[id(i,j)]) return 0;
}
return 1;
}
int main()
{
scanf("%d %d",&n,&m);
fo(i,1,n)
fo(j,1,m) ReadBit(a[id(i,j)]);
int k=1;
while (!check(k)) k<<=1;
printf("%d\n",k);
}