1. 程式人生 > >[HAOI2007]理想的正方形

[HAOI2007]理想的正方形

兩個 pac ati 之間 bsp () 格式 mono 正方形

題目描述

有一個a*b的整數組成的矩陣,現請你從中找出一個n*n的正方形區域,使得該區域所有數中的最大值和最小值的差最小。

輸入輸出格式

輸入格式:

第一行為3個整數,分別表示a,b,n的值

第二行至第a+1行每行為b個非負整數,表示矩陣中相應位置上的數。每行相鄰兩數之間用一空格分隔。

輸出格式:

僅一個整數,為a*b矩陣中所有“n*n正方形區域中的最大整數和最小整數的差值”的最小值。

輸入輸出樣例

輸入樣例#1:
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
輸出樣例#1:
1

說明

問題規模

(1)矩陣中的所有數都不超過1,000,000,000

(2)20%的數據2<=a,b<=100,n<=a,n<=b,n<=10

(3)100%的數據2<=a,b<=1000,n<=a,n<=b,n<=100

先求出每列往前n個的最小值和最大值,然後在用這個東西求出二維的往前上方n*n的正方形的最大值和最小值.
可以用一個set實時維護插入和刪除,復雜度
O(n^2log(n)).
更優的做法:用兩個單調隊列維護,每次隊首都是最大值或最小值,實時維護插入和刪除,插入是從後面開始比他大或小的都刪掉,維護單調性,因為每個點只會出入隊一次,復雜度O(n^2).

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<algorithm>
 7 #include<map>
 8 #include<complex>
 9
#include<queue> 10 #include<stack> 11 #include<cmath> 12 #include<set> 13 #include<vector> 14 #define maxn 1100 15 #define IT multiset<int>::iterator 16 using namespace std; 17 int mp[maxn][maxn],zx[maxn][maxn],zd[maxn][maxn],zx1[maxn][maxn],zd1[maxn][maxn]; 18 struct data{ 19 int head,tail,q[maxn],p[maxn]; 20 void clear(){head=1,tail=0;} 21 void push1(int key,int id){ 22 while(head<=tail && q[tail]>key)tail--; 23 q[++tail]=key,p[tail]=id; 24 } 25 void push2(int key,int id){ 26 while(head<=tail && q[tail]<key)tail--; 27 q[++tail]=key,p[tail]=id; 28 } 29 void pop(int id){ 30 while(p[head]<=id && head<=tail) head++; 31 } 32 int front(){ 33 return q[head]; 34 } 35 }q1,q2; 36 int main(){ 37 int n,m,k; 38 scanf("%d%d%d",&n,&m,&k); 39 for(int i=1;i<=n;i++) 40 for(int j=1;j<=m;j++) 41 scanf("%d",&mp[i][j]); 42 for(int i=1;i<=n;i++){ 43 q1.clear(); 44 q2.clear(); 45 for(int j=1;j<=k;j++) 46 q1.push1(mp[i][j],j),q2.push2(mp[i][j],j); 47 zx1[i][k]=q1.front();zd1[i][k]=q2.front(); 48 for(int j=k+1;j<=m;j++){ 49 q1.pop(j-k),q2.pop(j-k); 50 q1.push1(mp[i][j],j);q2.push2(mp[i][j],j); 51 zx1[i][j]=q1.front();zd1[i][j]=q2.front(); 52 } 53 } 54 for(int j=k;j<=m;j++){ 55 q1.clear(); 56 for(int i=1;i<=k;i++) 57 q1.push1(zx1[i][j],i); 58 zx[k][j]=q1.front(); 59 for(int i=k+1;i<=n;i++){ 60 q1.pop(i-k); 61 q1.push1(zx1[i][j],i); 62 zx[i][j]=q1.front(); 63 } 64 } 65 for(int j=k;j<=m;j++){ 66 q2.clear(); 67 for(int i=1;i<=k;i++) 68 q2.push2(zd1[i][j],i); 69 zd[k][j]=q2.front(); 70 for(int i=k+1;i<=n;i++){ 71 q2.pop(i-k); 72 q2.push2(zd1[i][j],i); 73 zd[i][j]=q2.front(); 74 } 75 } 76 int ans=2000000000; 77 for(int i=k;i<=n;i++) 78 for(int j=k;j<=m;j++) 79 ans=min(ans,zd[i][j]-zx[i][j]); 80 printf("%d",ans); 81 return 0; 82 }

[HAOI2007]理想的正方形