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开始;