1. 程式人生 > >[NOIP2018校模擬賽]T2矩陣分組 Matrix

[NOIP2018校模擬賽]T2矩陣分組 Matrix

第一個 開始 etc getch break src () 等價 mat

題目鏈接:

矩陣分組


分析:

這道題求的是兩部分極差當中大的那個的最小值。對於這種求最值的問題,我們很自然(其實並沒有)地想到二分答案。

這個題有兩個結論
(好像當時看出來了第一個?然後發現下面都不會了,果斷棄療滾去寫T3

第一個結論:

對於劃分的每個區域,為了保證只拐一次彎,它每一行的長度是單調且連續的

這樣任意兩個元素之間拐個直角彎就能到了(x)

參見下圖(從發的solution裏面扒的)
技術分享圖片

這個結論可以感性得到(……),因為如果它每一行的長度不單調,就會有 凸 ←這種形狀的東西出來,從它的一邊到另外一邊肯定是要拐至少兩個彎的

第二個結論:

矩陣A和矩陣B可以互換(即它們是等價的)

因為每個矩陣不管怎麽講總要占據一個角落(否則不滿足結論1),所以先考慮A占據左上角的情況,然後把它旋轉三次就能涵蓋到所有情況。
二分一個值mid(mid=min(max(gmaxi1-gmini1,gmaxi2,gmini2)),其上界為矩陣中最大值-最小值,下界為0,這樣最後的mid就是答案

對於check函數的思路:

因為矩陣中最大值和最小值不能在一個區域,否則這個max(gmaxi1-gmini1,gmaxi2,gmini2)就會很大,所以我們不妨設tot_max在A區域
從第一行開始找到第一個(找第一個是為了保證單調)與tot_max差值大於mid的值,這時候就跳出循環(這裏每一行的枚舉不能超過上一行的邊界),後面同理,處理出矩陣A,顯然這個矩陣A一定是滿足條件的
然後我們驗證剩下的部分(即矩陣B)當中的極差是否小於等於mid即可


代碼:

沒有代碼,因為我還沒寫出來(……)


#include<bits/stdc++.h>
using namespace std;
int n,m,x=1,x1=1,x2=n,x3=m,y=1,yy=n,y2=m,y3=1,t;
int tot_max=-(1<<20),tot_min=1<<20;
int a[4][2005][2005],endi[2005];  //endi中存儲A矩陣每行的邊界 
inline int read(){
    int cnt=0,f=1;char c;
    c=getchar();
    while(!isdigit(c)){
        if(c==‘-‘)f=-1;
        c=getchar();
    }
    while(isdigit(c)){
        cnt=cnt*10+c-‘0‘;
        c=getchar();
    }
    return cnt*f;
}
bool check(int kind,int x){
    if(kind&1) swap(n,m);  // 這裏第二和第四個矩陣是分別順時針逆時針旋轉了90°的,所以行數和列數需要交換 
    endi[0]=m;
    int tag;
    for(register int i=1,j;i<=n;i++){
        for(j=1;j<=endi[i-1];j++){
            if(tot_max-a[kind][i][j]>x)  //找到第一個與tot_max差值小於等於mid的值 
                break;
            }
            endi[i]=j-1;
        }
    for(register int i=1;i<=n;i++)
        for(register int j=endi[i]+1;j<=m;j++)  //處理第二個矩陣
            if(a[kind][i][j]-tot_min>x){
                if(kind&1) swap(n,m);  //如果剛剛交換了n和m,為了下次check,這裏需要換回來 
                return false;
            }
    if(kind&1) swap(n,m);
    return true;
}
bool tot_check(int x){
    if(check(0,x))return true;
    if(check(1,x))return true;
    if(check(2,x))return true;
    if(check(3,x))return true;
    return false;
}
int main(){
    n=read();m=read();
    x=1,x1=1,x2=n,x3=m,y=1,yy=n,y2=m,y3=1;
    for(register int i=1;i<=n;i++){  //讀入矩陣,讀入的時候就可以順手旋轉成四個矩陣了(順便這個旋轉很巧妙啊) 
        for(register int j=1;j<=m;j++){
            t=a[0][x][y++]=a[1][x1++][yy]=a[2][x2][y2--]=a[3][x3--][y3]=read();
            if(t>tot_max)tot_max=t;
            if(t<tot_min)tot_min=t;
        }
    x++,y=1,yy--,x1=1,x2--,y2=m,y3++,x3=m;
    }

    int l=0,r=tot_max-tot_min;
    int mid=(l+r)>>1;
    while(l<r){
        if(tot_check(mid)){
            r=mid;
            mid=(l+r)>>1;
        }
        else{
            l=mid+1;
            mid=(l+r)>>1;
        }
    }
    printf("%d",mid);
    return 0;
}

[NOIP2018校模擬賽]T2矩陣分組 Matrix