思路:
1. 小的边如果能组成大的,那肯定小的比大的优。所以枚举素数即可。(有367左右)
2. 复杂度分析,每次枚举的就是n*m/len,即n*m/2+n*m3+n*m/5…均摊下来应该是
O(n2)
的.
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define mem(a, b) memset(a, b, sizeof(a))
const int Maxn = 5000;
int num, prime[Maxn];
bool isprime[Maxn];
void init(){
num = 0;
mem(isprime, 0);
for(int i=2;i<=2500;i++){
if(isprime[i]) continue;
prime[++num] = i;
for(int j=i+i;j<=2500;j+=i) isprime[j] = 1;
}
}
char ma[Maxn][Maxn];
int n, m;
int sum[Maxn][Maxn];
int ans;
void kk(int len){
int temp, xnum, ynum, x, y, tmp1, tmp2;
xnum = n/len + ((n%len)?1:0);
ynum = m/len + ((m%len)?1:0);
temp = 0;
for(int i=1;i<=xnum;++i){
for(int j=1;j<=ynum;++j){
x = i * len;
y = j * len;
tmp1 = sum[x][y] - sum[x-len][y] - sum[x][y-len] + sum[x-len][y-len];
tmp2 = len * len - tmp1;
temp = temp + (tmp1 > tmp2 ? tmp2 : tmp1);
if(temp >= ans) return;
}
}
ans = ans < temp ? ans : temp;
}
void solve(){
int x;
mem(sum, 0);
for(int i=1;i<=4980;i++){
for(int j=1;j<=4980;j++){
if(i<=n && j<=m)
x = ma[i][j] - '0';
else x = 0;
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + x;
}
}
int len, mx;
ans = n*m;
mx = n > m ? n : m;
for(int i=1;i<=num;i++){
len = prime[i];
if(len>mx && prime[i-1]>mx) break;
kk(len);
}
printf("%d", ans);
}
int main(){
init();
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++)
scanf("%s", ma[i]+1);
solve();
return 0;
}