P2216 [HAOI2007]理想的正方形
阿新 • • 發佈:2018-02-19
sample radi pre nbsp esp log 空格 ron urn
題目描述
有一個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
很不錯的一道題,然而我只會用二維ST表做……(太弱了)
註意i+1<<5不是表示i+(1<<5),而是(i+1)<<5,害得我第一次只有10分(話說竟然有分???excuse me???)
因為正方形,我們設f[i][j][k]表示以(i,j)為左上角的長度為2^k的極值。
他可以看成長度為4個2^(k-1)正方形組成的,所以轉移方程很簡單,而且mn(記錄最小值)的數組不用初始化(想想,為什麽?)
答案時枚舉左上角即可,利用RMQ的思想就行了……
AC代碼如下:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1000+5;
const int M=10+5;
int mn[N][N][M],mx[N][N][M],n,a,b,x,ans=1<<30,m;
void init()
{
for(int k=1;k<=11;k++)
for(int i=1;i+(1<<k)-1<=a;i++)
for(int j=1;j+(1<<k)-1<=b;j++)
mx[i][j][k]=max(max(mx[i][j][k-1],mx[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),max(mx[i+(1<<(k-1))][j][k-1],mx[i][j+(1<<(k-1))][k-1])),
mn[i][j][k]=min(min(mn[i][j][k-1],mn[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),min(mn[i+(1<<(k-1))][j][k-1],mn[i][j+(1<<(k-1))][k-1]));
return;
}
int q(int x1,int y1)
{
int x2=x1+n-(1<<m),y2=y1+n-(1<<m);
return max(max(mx[x1][y1][m],mx[x2][y2][m]),max(mx[x1][y2][m],mx[x2][y1][m]))-min(min(mn[x1][y1][m],mn[x2][y2][m]),min(mn[x2][y1][m],mn[x1][y2][m]));
}
int main()
{
scanf("%d%d%d",&a,&b,&n);
m=log(n)/log(2);
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
scanf("%d",&x),mn[i][j][0]=mx[i][j][0]=x;
init();
for(int i=1;i+n-1<=a;i++)
for(int j=1;j+n-1<=b;j++)
ans=min(ans,q(i,j));
printf("%d",ans);
return 0;
}
P2216 [HAOI2007]理想的正方形