题意:已知n*m的矩阵,由1,0构成,要求确定一个k,使得n*m的矩阵划分成一系列k*k的小矩阵,并且k*k矩阵内的所有值都要相同(要么都为1,要么都为0)。 (可以补行或列,补0)

思路:遍历k(1~2500) , 对于每一个k,我们处理出当前k所需要改变的所有次数。 首先,我们预处理出(1,1)~(i,j)【任意一点】区域中’1’的个数dp[i][j],那么对于当前k*k的区域,我们所要改变的就是 : dp[i][j]-dp[i-k][j]-dp[i][j-k] + dp[i-k][j-k],对于每一个k,累加比较,求出最小的次数。

错误分析:瞎猜,以为2肯定是最小的,所以k恒等于2 , 然后瞎搞搞就wa了5发。

数据分析:2 ≤ n, m ≤ 2 500 k<=max(n,m) <=2500

复杂度分析: O(k*n/k*m/k)=O(m*n/k) 还是很可观的复杂度

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char mp[5050][5050];
int n,m;
int dp[5050][5050];
ll a=0;
ll minn=LONG_LONG_MAX;

void init() // 预处理——关键
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=5050-1;i++)
        for(int j=1;j<=5050-1;j++)
           dp[i][j]= mp[i][j]=='1' ? dp[i][j-1]+1: dp[i][j-1];
    for(int i=1;i<=5050-1;i++)
        for(int j=1;j<=5050-1;j++)
            dp[i][j]+=dp[i-1][j];
}

ll solve()
{
    int t=max(n,m);
    for(int k=2;k<=t;k++)
    {
        a=0;
        for(int i=k;i<=n+k ;i+=k)
        {
            for(int j=k;j<=m+k ;j+=k)
            {
                int temp=dp[i][j]-dp[i-k][j]-dp[i][j-k]+dp[i-k][j-k];
                //printf("k=%d i=%d j=%d temp=%d\n",k,i,j,temp);
                a+=1LL*min(temp,k*k-temp);
            }
        }
        if(a<minn)  minn=a;
    }
    return minn;
}

int main(void)
{
    cin >> n>> m;
    for(int i=1;i<=n;i++)
        scanf("%s",mp[i]+1);
    init();
    /*for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);*/
    ll ans=solve();
    cout << ans << endl;
}