1. 程式人生 > >NOIP模擬——矩陣分組

NOIP模擬——矩陣分組

數字 spa bsp 模擬 name 允許 isdigit 表示 code

有N行M列的矩陣,每個格子中有一個數字,現在需要你將格子的數字分為A,B兩部分

要求:

1、每個數字恰好屬於兩部分的其中一個部分

2、每個部分內部方塊之間,可以上下左右相互到達,且每個內部方塊之間可以相互到達,且最多拐一次彎

如:

AAAAA  AAAAA  AAAAA
AABAA  BaAAA  AAABB
ABBBA  BBAAA  AAABB
AABAA  BaAAA  ABBBB
AAAAA  AAAAA  BBBBB

  (1)     (2)     (3) 

其中(1)(2)是不允許的分法,(3)是允許的分法。在(2)中,a屬於A區域,這兩個a元素之間互相到達,但是不滿足只拐一次彎到達。

問:對於所有合法的分組中,A區域和B區域的極差,其中極差較大的一個區域最小值是多少

提示:極差就是區域內最大值減去最小值。

輸入

第一行兩個正整數n,m

接下來n 行,每行m個自然數A_{i,j}表示權值

輸出

輸出一行表示答案

樣例輸入
4 4
1 12 6 11
11 4 2 14
10 1 9 20
4 17 13 10
樣例輸出
11
提示

【樣例解釋】 1 12 6 11 11 4 2 14 10 1 9 20 4 17 13 10

分法不唯一,如圖是一種合法的分法。左邊部分極差12-1=11,右邊一塊極差20-10=10,所以答案取這兩個中較大者11。沒有別的分法,可以使答案更小。

測試點N,m範圍
1,2 n<=10,m<=10
3-4 n=1,m<=2000
5-7 n<=200,m<=200
8-10 n<=2000,m<=2000

所有權值1<=a_ij<=10^9

肯定是二分答案了,枚舉最大的極差,帶入到最大值所在的區域內,區域分好後再判斷是否滿足

可以證明分好的區域邊緣必然是一個樓梯樣的,高度遞減的(我覺得不用證明吧)

而且每個區域必定會占一個角,

而且最大和最小的肯定不能在同一個區域,否則還玩啥啊

如果我們從最大值所在的區域來看的話

可能會分別在不同的角上

而在不同的角判斷的方法不一樣

因為寫好幾種判斷太麻煩了

所以直接存把矩陣旋轉90.180.270度的情況一起存下來

相當於默認角在某一個位置,這樣就可以用一種判斷的方法就可以把所有情況都判斷完了

不過存儲的寫法很是巧妙啊

看代碼吧

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
int n,m,a[4][2005][2005],gmax=-2e9-1,gmin=2e9+1,endi[2005];
inline bool check(int u,int k)
{
    if(u&1) swap(m,n);
    endi[0]=m;
    for(int i=1,j;i<=n;i++)
    {
        for(j=1;j<=endi[i-1];j++)
        {
            if(gmax>a[u][i][j]+k)
            break;
        }
        endi[i]=j-1;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=endi[i]+1;j<=m;j++)
        {
            if(a[u][i][j]>gmin+k)
            {
                if(u&1) swap(m,n);
                return false;
            }
        }
    }
    if(u&1) swap(m,n);
    return true;
}
inline bool che(int k)
{
    for(int i=0;i<4;i++)
    {
        if(check(i,k)) return true;
    }
    return false;
}
int main(){
    n=read(),m=read();
    int x=1,x1=1,x2=n,x3=m,y=1,y1=n,y2=m,y3=1,t;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            t=a[0][x][y++]=a[1][x1++][y1]=a[2][x2][y2--]=a[3][x3--][y3]=read();
            if(t>gmax)gmax=t;
            if(t<gmin) gmin=t;
        }
        x++,y=1;
        y1--,x1=1;
        x2--,y2=m;
        y3++,x3=n;
    }
    int l=0,r=gmax-gmin;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(che(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l<<endl;
    return 0;
}

NOIP模擬——矩陣分組