其他分享
首页 > 其他分享> > JOI2017 JOIOI王国

JOI2017 JOIOI王国

作者:互联网

JOIOI王国 JOI2017 题解

因为题目是最大值最小,所以考虑二分答案,观察题目中的划分方案可以发现,最后的划分的那条边界线一定是最后分成了个梯形的形状,即分界点单调不降或不升。因为是要二分,所以我们假设王国格子的最小值在左边,最大值在右边,分界线划出来的左边是个下梯形,即上底大于等于下底。那么直接一行一行的扫过去,比较一下就行(具体的康康代码)

问题就是,这种划分情况只是我们假设的(最小值左最大值右下梯形),所以每次把这个矩形顺时针旋转90°,转四次,每次二分一下就行

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
const int inf=0x3f3f3f3f;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int n,m;
int a[maxn][maxn][3],op,maxv=-inf,minv=inf;
bool check(int x)
{
	int lst=m;
	for(int i=1;i<=n;i++)
	{
		int nw=lst;
		for(int j=1;j<=lst;j++)
		{
			if(a[i][j][op]-minv>x)
			{
				nw=j-1;
				break;
			}
		}
		for(int j=nw+1;j<=m;j++)
			if(maxv-a[i][j][op]>x)
				return false;
		lst=nw;
	}
	return true;
}
int main()
{
	freopen("joioi.in","r",stdin);
	freopen("joioi.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			a[i][j][0]=read();
			maxv=max(maxv,a[i][j][0]);
			minv=min(minv,a[i][j][0]);
		}
	}
	int ans=inf;
	for(int i=1;i<=4;i++)
	{
		int l=0,r=maxv-minv,res=0;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(check(mid))
			{
				r=mid-1;
				res=mid;
			}
			else
				l=mid+1;
		}
		ans=min(ans,res);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				a[m-j+1][i][op^1]=a[i][j][op];
		op^=1;
		swap(n,m);
	}
	cout<<ans<<endl;
	return 0;
}

标签:ch,JOI2017,int,最大值,mid,JOIOI,read,王国,nw
来源: https://www.cnblogs.com/zxi8-may/p/16300736.html