zoukankan      html  css  js  c++  java
  • 【Luogu】P3933 Chtholly Nota Seniorious

    【题意】将n*m矩阵分成两个区域,要求满足一定条件,求两区域内部极差较大值最小。n,m<=2000

    【算法】二分

    【题解】极差的数值满足单调性,所以考虑二分极差。

    对于给定的极差,将所有数值排序后,1~a[n*m]-num-1必须选择A,a[1]+num+1~n*m必须选择B,其它不要求。(开始的时候想二分图染色,后来发现排序一下规律就十分明显了)

    现在问题转化为矩阵中已知一些格子选A,一些格子选B,求能否组成合法方案。

    观察要求满足的条件,很容易得出结论:分界线必须单调,所以就有上A下B或上B下A,递增或递减,组合成四种情况。

    针对上B下A,递增的情况(其他情况类似),对于每一列,找到最下面的B和最上面的A,维护A的递增同时看B是否严格在A上方。

    复杂度O(n*m log max(Ai))。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a<b?b:a;}
    int abs(int x){return x>0?x:-x;}
    void mins(int &a,int b){if(a>b)a=b;}
    void maxs(int &a,int b){if(a<b)a=b;}
    //void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    /*------------------------------------------------------------*/
    const int inf=0x3f3f3f3f,maxn=2010;
    
    int n,m,A,B,tot,a[maxn*maxn],c[maxn*maxn],minA[maxn],minB[maxn],maxA[maxn],maxB[maxn];
    struct cyc{int id,num;}b[maxn*maxn];
    bool cmp(cyc a,cyc b){return a.num<b.num;}
    int find(int x,int y){
        int id=c[(x-1)*m+y];
        if(id<A)return 0;
        if(A<=id&&id<B)return 1;
        return 2;
    }
    bool check(int number)
    {
        bool ok=1;int num;
        A=lower_bound(a+1,a+tot+1,a[tot]-number)-a;
        B=upper_bound(a+1,a+tot+1,a[1]+number)-a;
        if(A>B)return 0;
        memset(maxA,0x3f,sizeof(maxA));memset(maxB,0x3f,sizeof(maxB));
        memset(minA,0,sizeof(minA));memset(minB,0,sizeof(minB));
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(find(j,i)==0&&maxA[i]==inf)maxA[i]=j;
                if(find(j,i)==2&&maxB[i]==inf)maxB[i]=j;
                if(maxA[i]!=inf&&maxB[i]!=inf)break;
            }
            for(int j=n;j>=1;j--){
                if(find(j,i)==0&&!minA[i])minA[i]=j;
                if(find(j,i)==2&&!minB[i])minB[i]=j;
                if(minA[i]&&minB[i])break;
            }
        }
        num=n+1;ok=1;
        for(int i=1;i<=m;i++){
            num=min(num,maxA[i]);
            if(minB[i]>=num){ok=0;break;}
        }
        if(ok)return 1;
        
        num=n+1;ok=1;
        for(int i=1;i<=m;i++){
            num=min(num,maxB[i]);
            if(minA[i]>=num){ok=0;break;}
        }
        if(ok)return 1;
        
        num=n+1;ok=1;
        for(int i=m;i>=1;i--){
            num=min(num,maxA[i]);
            if(minB[i]>=num){ok=0;break;}
        }
        if(ok)return 1;
        
        num=n+1;ok=1;
        for(int i=m;i>=1;i--){
            num=min(num,maxB[i]);
            if(minA[i]>=num){ok=0;break;}//
        }
        if(ok)return 1;
        
        return 0;
    }    
    int main()
    {
        n=read();m=read();    
        int l=0,r=0,mid;
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
            int num=read();r=max(r,num);
            b[++tot]=(cyc){(i-1)*m+j,num};
        }
        sort(b+1,b+tot+1,cmp);
        for(int i=1;i<=tot;i++)c[b[i].id]=i;
        for(int i=1;i<=tot;i++)a[i]=b[i].num;
        while(l<r)
        {
            mid=(l+r)>>1;
            if(check(mid))r=mid;else l=mid+1;
        }
        printf("%d",l);
        return 0;
    }
    View Code
  • 相关阅读:
    store 加载异常处理与加载信息提示
    jQuery和ExtJS的timeOut超时问题和event事件处理问题
    Virtualbox虚拟机安装CentOS6.5图文详细教程
    虚拟机
    20180104 wdcp中的mysql重启不成功
    MySQL取得某一范围随机数(MySQL随机数)
    安装lszrz,用于上传文件
    cpu占用高 20180108
    怎么实时查看mysql当前连接数
    数据库SQL优化大总结之 百万级数据库优化方案
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7708933.html
Copyright © 2011-2022 走看看