您的位置:首页 > 其它

洛谷10月月赛R2·浴谷八连测R3 T2

2017-10-28 08:30 363 查看
传送门

不能转两次弯说明什么?

把图分成两个部分其实就相当于画一条单调的线。

如下图


如果我们分蓝色的,以上面那一行为最大,那么下面的蓝色的终点是不可以超过上面那行的。

但是蓝色既可以左右延伸,也可以上下延伸。

可以从4个方向出发。

但是写4个分色有些麻烦。

我们可以用从左开始,向右延伸的方法,然后分别把图选择90,180,270.

就可以得到所有的情况了。

得到了图该怎样做?

二分答案。

我们首先得到最大值与最小值。

答案肯定小于最大值-最小值。

假定最大值在蓝色,最小值在红色。

二分一个答案,用最大值-元素>=ans为条件去构造蓝色块。

然后再去判断红色块中的元素是不是都满足条件即可。

#include <cstdio>
#include <iostream>
using namespace std;
const int inf=1e9;
int n,m,a[2010][2010],ans=inf,maxx=-inf,minx=inf;
void turn90()//对调
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m/2;j++)
swap(a[i][j],a[i][m-j+1]);
}
void turnd()//选择
{
for(int i=1;i<=n/2;i++)
for(int j=1;j<=m;j++)
swap(a[i][j],a[n-i+1][j]);
}
bool check(int mid)
{
int p=m+1;
for(int i=1;i<=n;i++)
{
int t=0;
for(int j=1;j<=min(p,m);j++)
if(maxx-a[i][j]<=mid) t=max(t,j);//找i行的最大延伸
else break;
p=t;
for(int j=t+1;j<=m;j++)
if(a[i][j]-minx>mid) return 0;//满不满足条件
}
return 1;
}
int get_ans()
{
int l=0,r=maxx-minx+1;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),maxx=max(a[i][j],maxx),minx=min(a[i][j],minx);
ans=min(ans,get_ans());
turn90();
ans=min(ans,get_ans());
turnd();
ans=min(ans,get_ans());
turn90();
ans=min(ans,get_ans());//枚举4种情况
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: