就是给你个 n × m n\times m n×m 的矩阵,为了使其的任意长度为偶数的正方形子矩阵里要含有奇数个 1 1 1 最少要改变几个 a i , j a_{i,j} ai,j 的状态。
首先可以知道 4 × 4 4\times 4 4×4 的合法矩阵是不存在的,那么 min ( n , m ) > 3 \min(n,m)>3 min(n,m)>3 的矩阵也是不存在的。
那么我们只要分类讨论分别 min ( n , m ) = 1 , 2 , 3 \min(n,m)={1,2,3} min(n,m)=1,2,3 的情况即可。
我们在这边钦定 n ≤ m , n ≤ 3 n\leq m,n\leq 3 n≤m,n≤3
对于 n = 1 n=1 n=1 的情况由于不存在偶数长度的子矩阵直接输出 0 0 0
对于 n = 2 , 3 n=2,3 n=2,3 的情况我们考虑dp。设 f i , j , k , p f_{i,j,k,p} fi,j,k,p 表示到第 i i i 列 a 3 , i = j , a 2 , i = k , a 1 , i = p a_{3,i}=j,a_{2,i}=k,a_{1,i}=p a3,i=j,a2,i=k,a1,i=p 的最少需要改变的个数。
那么就是很显然的转移,只有当每个 2 × 2 2\times 2 2×2 的小矩阵的 1 1 1 的个数为奇数转移,具体地就是刷表法吧。
时间复杂度 O ( max ( n , m ) × 2 2 × min ( n , m ) ) O(\max(n,m)\times2^{2\times\min(n,m)}) O(max(n,m)×22×min(n,m))
const int mod=1e9+7;
const int mo=998244353;
const int N=1e6+5;
int n,m,f[N][2][2][2],a[4][N];
char str[N];
int main()
{
io.read(n),io.read(m);
if(min(n,m)>3)GG;
if(n<m)
{
For(i,1,n)
{
scanf("%s",str+1);
For(j,1,m) a[i][j]=str[j]^48;
}
}
else
{
For(i,1,n)
{
scanf("%s",str+1);
For(j,1,m) a[j][i]=str[j]^48;
}
swap(n,m);
}
if(n==1) return printf("0\n"),0;
if(n==2)
{
For(i,0,1) For(j,0,1) f[1][i][j][0]=(i!=a[2][1])+(j!=a[1][1]);
For(i,2,m) For(j,0,1) For(k,0,1) f[i][j][k][0]=1e9;
For(i,2,m) For(j,0,1) For(k,0,1)
For(l,0,1) For(p,0,1) if((k+j+l+p)&1)
{
int s=2-((j==a[2][i])+(k==a[1][i]));
f[i][j][k][0]=min(f[i][j][k][0],f[i-1][l][p][0]+s);
}
int ans=1e9;
For(i,0,1) For(j,0,1) ans=min(ans,f[m][i][j][0]);
io.write(ans);
return 0;
}
For(i,0,1) For(j,0,1) For(k,0,1)
{
f[1][i][j][k]=3-((a[3][1]==i)+(a[2][1]==j)+(a[1][1]==k));
For(l,2,m) f[l][i][j][k]=1e9;
}
For(l,2,m) For(i,0,1) For(j,0,1) For(k,0,1)
For(ii,0,1) For(jj,0,1) For(kk,0,1) if(((kk+k+jj+j)&1)&&((jj+j+i+ii)&1))
{
int s=3-((a[3][l]==i)+(a[2][l]==j)+(a[1][l]==k));
f[l][i][j][k]=min(f[l-1][ii][jj][kk]+s,f[l][i][j][k]);
}
int ans=1e9;
For(i,0,1) For(j,0,1) For(k,0,1) ans=min(ans,f[m][i][j][k]);
io.write(ans);
return 0;
}