习题:JOIOI王国(二分)

题目

传送门

思路

如果我们从正向开始思考,

也就是像笔者这个蒻鸡一样开始思考DP

你就会发现每一个DP值需要有4个辅助数组来转移

而且当前的DP值对后续的DP值都还有影响

但是换一个思路思考,

很容易可以发现答案是具有单调性的

也就是说二分

最终的形状一定是一个梯形

接着你在梯形内寻找最小值,再用二分的答案求出最大值

检验的时间复杂度就为\(O(n*m)\)

外加二分的复杂度\(O(log_{maxa})\)

如果是1S,还是有点卡常

但是出题人善良的开了4S

代码

#include<iostream>
#include<climits>
#include<cstring>
using namespace std;
int n,m;
int a[2005][2005];
int b[2005][2005];
int c[2005][2005];
int d[2005][2005];
int h[2005];
int minn=INT_MAX;
int maxx=INT_MIN;
int l=INT_MAX;
int r=INT_MIN;
int mid;
bool dfs(int x,int t[2005][2005])
{
    memset(h,0,sizeof(h));
    h[n+1]=m;
    for(int i=n;i>=1;i--)
    {
        while(h[i]<h[i+1]&&t[i][h[i]+1]-minn<=x)
            h[i]++;
    }
    int minnh=INT_MAX;
    for(int i=1;i<=n;i++)
        for(int j=h[i]+1;j<=m;j++)
            minnh=min(minnh,t[i][j]);
    if(maxx-minnh<=x)
        return 1;
    return 0;   
}
bool pd(int cnt)
{
    if(dfs(cnt,a)||dfs(cnt,b)||dfs(cnt,c)||dfs(cnt,d))
        return 1;
    return 0;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
            d[i][j]=c[i][j]=b[i][j]=a[i][j];
            minn=min(minn,a[i][j]);
            maxx=max(maxx,a[i][j]);
        }
    }
    for(int i=1;i<=n/2;i++)
        swap(b[i],b[n-i+1]);
    for(int i=1;i<=n/2;i++)
        swap(c[i],c[n-i+1]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m/2;j++)
        {
            swap(c[i][j],c[i][m-j+1]);
            swap(d[i][j],d[i][m-j+1]);
        }
    }
    l=0;
    r=maxx-minn;
    while(l<r)
    {
        mid=(1ll*l+r)>>1;
        if(pd(mid))
            r=mid;
        else
            l=mid+1;
    }
    cout<<l;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/11961906.html
今日推荐