using System;
using System.Collections;
using System.Collections.Generic;
public class Program {
public static int[,] field;//每块地的价值
public static int[,] sum;//从0,0到某一点的矩形地的总价值
public static void Main() {
string line;
while ((line = System.Console.ReadLine ()) !=
null) { // 注意 while 处理多个 case
string[] tokens = line.Split(' ');
int n = int.Parse(tokens[0]);
int m = int.Parse(tokens[1]);
field = new int[n, m];
sum = new int[n + 1, m + 1];
for (int i = 0; i < n; i++) {
line = Console.ReadLine();
for (int j = 0; j < m; j++) {
field[i, j] = line[j] - '0';
}
}
//给sum赋值
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int temp = 0;
for (int k = 0; k < i; k++) {
for (int l = 0; l < j; l++) {
temp += field[k, l];
}
}
sum[i, j] = temp;
}
}
//穷举竖向3刀,划分横向3刀时,符合条件则划一刀,用count计算符合条件的行,count==4则代表每块位置的价值都大于min
int left = 0;
int right = sum[n,m] / 16 + 1;
int ans = 0;
while(left <= right){
int min = (left + right) / 2;
bool flag = false;
for(int i = 1; i <= m - 3; i++){//i是第一刀的位置
for(int j = i + 1; j <= m - 2; j++){//j是第二刀的位置
for(int k = j + 1; k <= m - 1; k++){//k是第三刀的位置
//对于这种割法,依次判断是否可以割出最小价值>=min的三刀横向刀
int lastcut = 0;
int count = 0;
for(int l = 1; l <= n; l++){
bool s1 = judge(lastcut,0,l,i,min);
bool s2 = judge(lastcut,i,l,j,min);
bool s3 = judge(lastcut,j,l,k,min);
bool s4 = judge(lastcut,k,l,m,min);
if(s1 && s2 && s3 && s4){
lastcut = l;
count++;
}
}
if(count >= 4) {
flag = true;
break;
}
}
if(flag) break;
}
if(flag) break;
}
if(flag){
ans = min;
left = min + 1;
}else{
right = min - 1;
}
}
Console.WriteLine(ans);
}
}
//判断两个顶点之间的田地的价值是否大于num
public static bool judge(int x1, int y1, int x2, int y2, int num){
int _temp = sum[x2,y2] - sum[x2,y1] - sum[x1,y2] + sum[x1,y1];
if(Math.Abs(_temp) >= num) return true;
else return false;
}
}
C#需要把时间抠的好死,用二分查找,还有一个细节,16块田地中,最小的田地最大化,这块地一定不能大于田地总价值/16,所以可以把二分查找的右指针设置成sum[n,m]/16 +1开始;

京公网安备 11010502036488号