【JZOJ3918】蛋糕

description

今天是Bessie的生日,他買了一個蛋糕和朋友們一起分享,蛋糕可以看成是一個R行C列的表格,共有R*C個格子,每個格子都有一個0至9的數字,表示該格子蛋糕擁有的巧克力。現在Bessie要把蛋糕橫的切3刀再豎的切3刀,由於Bessie刀法厲害,所以每個格子蛋糕都是完整的,顯然蛋糕會被切成16份,然後Bessie和他的15個朋友們每人拿一份,Bessie比較客氣,總是等其他朋友拿完了,Bessie拿最後剩下的那一份。Bessie的朋友們都很不客氣,都是挑最多巧克力的那份去拿,於是Bessie最後拿到手的那份蛋糕總是巧克力總和最少的。Bessie心想:既然自己總是最後拿蛋糕,那應該怎麼切蛋糕,才能使得自己拿的那部分蛋糕的有儘量多的巧克力呢?這個問題自然是你的任務了。


analysis

  • 要求最大值最小,先二分一個答案

  • 對於豎行,O(n3)O(n^3)枚舉切哪三列,然後剩下用三個二分找出可以滿足條件的最小矩形

  • 如果十六個矩形的和的最小值都大於二分的答案則可以把答案取大,否則取小

  • 時間複雜度O(n3log2n)O(n^3log^2n)


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 105
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)

using namespace std;

ll a[MAXN][MAXN],sum[MAXN][MAXN];
ll n,m,num;

inline ll get(ll x,ll y,ll xx,ll yy){return sum[xx][yy]-sum[x-1][yy]-sum[xx][y-1]+sum[x-1][y-1];}
inline bool judge(ll x)
{
	fo(i,1,m-1)fo(j,i+1,m-1)fo(k,j+1,m-1)
	{
		ll l=1,r=n,mid,las;
		while (l<r)mid=(l+r)>>1,min(min(get(1,1,mid,i),get(1,i+1,mid,j)),min(get(1,j+1,mid,k),get(1,k+1,mid,m)))>=x?r=mid:l=mid+1;
		if (!r)continue;

		las=l=r+1,r=n;
		while (l<r)mid=(l+r)>>1,min(min(get(las,1,mid,i),get(las,i+1,mid,j)),min(get(las,j+1,mid,k),get(las,k+1,mid,m)))>=x?r=mid:l=mid+1;
		if (r<las)continue;

		las=l=r+1,r=n;
		while (l<r)mid=(l+r)>>1,min(min(get(las,1,mid,i),get(las,i+1,mid,j)),min(get(las,j+1,mid,k),get(las,k+1,mid,m)))>=x?r=mid:l=mid+1;
		if (r<las)continue;

		if (min(min(get(r+1,1,n,i),get(r+1,i+1,n,j)),min(get(r+1,j+1,n,k),get(r+1,k+1,n,m)))>=x)return 1;
	}
	return 0;
}
int main()
{
	//freopen("T1.in","r",stdin);
	scanf("%lld%lld\n",&n,&m);
	fo(i,1,n){fo(j,1,m)num+=(a[i][j]=getchar()-'0');scanf("\n");}
	fo(i,1,n)fo(j,1,m)sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
	ll l=0,r=num/16,mid;
	while (l<=r)mid=(l+r)>>1,judge(mid)?l=mid+1:r=mid-1;
	printf("%lld\n",r);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章