jzoj蛋糕【二分】【枚举】

>Description
一个R行C列的表格,共有R*C个格子,每个格子都有一个0至9的数字,表示该格子的价值。现在要把格子横分4份再竖分4份,表格总共会被分成16份,求出在什么情况下,价值最小的那份价值最大。


>Input
第一行,两个整数R,C。
接下来有R行,每行有C个整数,每个整数范围是0至9。

>Output
一个整数,表示最小的价值。


>Sample Input
5 5
95998
21945
23451
99798
74083

>Sample Output
3

40%的数据, 4 <= R,C <= 10。
60%的数据, 4 <= R,C <= 20。
100%的数据, 4 <= R,C <= 75。


>解题思路

数据并不大,所以可以先枚举竖切的3刀在哪(切三刀变成四份),然后在看横切的。
这里就可以用到二分,二分表格中可以切出来的的最小价值,在已知竖切的位置的情况下,可不可以横切成16个格子,并且可以切出二分中mid的价值。

横切>>>枚举每一行,看看每一行中的被竖切成的四个格子,有没有大于等于目标价值,如果是,就横切一刀;如果小于目标价值,那么表格中的最小价值就不是目标价值了,所以就继续往下合并格子(也就是不切当前的那一行),直到切成的四个格子都大于等于目标价值。


>代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n, m, a[80][80], ans, minn, maxn, s[4], sum[80][80], p[5];

bool check (int t)
{
	memset (p, 0, sizeof (p));
	int c = 0; //累计可以切出来的横切个数
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= 3; j++)
		  p[j] += sum[i][s[j]] - sum[i][s[j - 1]];
		p[4] += sum[i][m] - sum[i][s[3]]; //计算四个格子的价值
		if (p[1] >= t && p[2] >= t && p[3] >= t && p[4] >= t)
		{
			c++;
			memset (p, 0, sizeof (p)); //清0数组,继续计算下一行
		}
	}
	if (c < 4) return 0;
	return 1;
}

void work ()
{
	int l = minn, r = maxn, mid;
	while (l < r)
	{
		mid = (l + r + 1) / 2; //hkydalao说r=mid-1的情况下,mid一般要取(l+r+1)/2
		if (check (mid)) l = mid; //如果横切可以切出mid,那么就继续取更大的目标
		else r = mid - 1;
	}
	ans = max (ans, l); //最小价值中最大的那个
}

int main()
{
	scanf ("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
	  for (int j = 1; j <= m; j++)
	  {
	  	 scanf("%1d", &a[i][j]); //在jzoj上这样交才能对
		 sum[i][j] = a[i][j] + sum[i][j - 1]; //每一行的前缀和
		 minn = min (minn, a[i][j]); //二分中l的取值
		 maxn += a[i][j]; //二分中r的取值
	  }
	maxn /= 16; //所有格子的和太大了,而且也没有必要,所以就按照hkydalao所说,取一个分成16个格子的平均值
	for (s[1] = 1; s[1] <= m - 3; s[1]++)
	  for (s[2] = s[1] + 1; s[2] <= m - 2; s[2]++)
	    for (s[3] = s[2] + 1; s[3] <= m - 1; s[3]++) //枚举竖切的位置
	      work (); //进行二分
	printf ("%d", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值