歌名 - 歌手
0:00

    【NOIP2014模拟11.3】蛋糕

    题目

    今天是Bessie的生日,他买了一个蛋糕和朋友们一起分享,蛋糕可以看成是一个R行C列的表格,共有R*C个格子,每个格子都有一个0至9的数字,表示该格子蛋糕拥有的巧克力。现在Bessie要把蛋糕横的切3刀再竖的切3刀,由于Bessie刀法厉害,所以每个格子蛋糕都是完整的,显然蛋糕会被切成16份,然后Bessie和他的15个朋友们每人拿一份,Bessie比较客气,总是等其他朋友拿完了,Bessie拿最后剩下的那一份。Bessie的朋友们都很不客气,都是挑最多巧克力的那份去拿,于是Bessie最后拿到手的那份蛋糕总是巧克力总和最少的。Bessie心想:既然自己总是最后拿蛋糕,那应该怎么切蛋糕,才能使得自己拿的那部分蛋糕的有尽量多的巧克力呢?这个问题自然是你的任务了。

    分析

    要求最大值最小,自然考虑到二分答案,
    那么暴力枚举横切的三条边,
    将竖切的三条边用三次二分来找出来,如果无法找出这缩小二分出的答案。
    时间复杂度\(O(log_2(\dfrac{sum}{16})n^33log_2n)\)

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const int maxlongint=2147483647;
    const int mo=1000000007;
    const int N=85;
    using namespace std;
    int a[N][N],n,m,sum[N][N],d[4];
    int val(int x,int y,int x1,int y1)
    {
    	return sum[x1][y1]-sum[x-1][y1]-sum[x1][y-1]+sum[x-1][y-1];
    }
    int rf(int l,int r,int v)
    {
    	int t=l;
    	while(l<r)
    	{
    		int mid=(l+r)/2;
    		if(v<=min(val(1,t,d[1],mid),min(val(d[1]+1,t,d[2],mid),min(val(d[2]+1,t,d[3],mid),val(d[3]+1,t,n,mid))))) r=mid;
    		else
    			l=mid+1;
    	}
    	return l;
    }
    bool ok(int v)
    {
    	int pos=1,np=0;
    	np=rf(pos,m+1,v);
    	if(np==m+1) return false;
    	pos=np+1;
    	np=rf(pos,m+1,v);
    	if(np==m+1) return false;
    	pos=np+1;
    	np=rf(pos,m+1,v);
    	if(np==m+1) return false;
    	pos=np+1;
    	np=rf(pos,m+1,v);
    	if(np==m+1) return false;
    	return true;
    }
    bool dg(int x,int j,int v)
    {
    	if(x>3)
    	{
    		if(val(j,1,n,m)<v*4) return false;
    		if(ok(v)) return true;
    		else 
    		return false;
    	}
    	for(int i=j;i<=n;i++)
    	{
    		if(val(j,1,i,m)>=v*4)
    		{
    			d[x]=i;
    			if(dg(x+1,i+1,v)) return true;
    		}
    	}
    	return false;
    }
    int main()
    {
    	scanf("%d%d\n",&n,&m);
    	int num=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			char c=getchar();
    			while(c<'0' ||  c>'9') c=getchar();
    			a[i][j]=c-'0';
    			num+=a[i][j];
    		}
    	for(int i=1;i<=n;i++) a[i][m+1]=100;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m+1;j++)
    			sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    	int l=0,r=num/16;
    	while(l+1<r)
    	{
    		int mid=(l+r)/2;
    		if(dg(1,1,mid)) l=mid;
    		else r=mid;
    	}
    	if(dg(1,1,r)) printf("%d",r);
    	else printf("%d",l);
    }
    
    posted @ 2018-05-22 12:13  无尽的蓝黄  阅读(244)  评论(0编辑  收藏  举报