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

49 篇文章 0 订阅
39 篇文章 0 订阅

传送门
不能转两次弯说明什么?
把图分成两个部分其实就相当于画一条单调的线。
如下图这里写图片描述
如果我们分蓝色的,以上面那一行为最大,那么下面的蓝色的终点是不可以超过上面那行的。
但是蓝色既可以左右延伸,也可以上下延伸。
可以从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);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值