[HAOI2007]理想的正方形
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2007]理想的正方形相关的知识,希望对你有一定的参考价值。
题目描述
有一个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
这题大多用的是单调队列或二维线段树(卡常)
但标签有dp
于是用dp的方法
f[i][j][k]表示左上(i,j),边长为k时的最大值
f[i][j][k]=max(f[i][j][k-1],f[i+1][j][k-1],f[i][j+1][k-1],f[i+1][j+1][k-1])
复杂度为O(abn)会超时
这里用倍增,f[i][j][k]表示左上(i,j)边长为2^k
f[i][j][k]=max(f[i][j][k-1],f[i+2^(k-1)][j][k-1],f[i][j+2^(k-1)][k-1],f[i+2^(k-1)][j+2^(k-1)][k-1])
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int f1[2001][2001],f2[2001][2001],ans,a,b,n; 8 int logn; 9 int query(int x,int y) 10 {int maxv=0,minv=0; 11 maxv=max(f1[x][y],max(f1[x+n-(1<<logn)][y],max(f1[x][y+n-(1<<logn)],f1[x+n-(1<<logn)][y+n-(1<<logn)]))); 12 minv=min(f2[x][y],min(f2[x+n-(1<<logn)][y],min(f2[x][y+n-(1<<logn)],f2[x+n-(1<<logn)][y+n-(1<<logn)]))); 13 return maxv-minv; 14 } 15 int main() 16 {int i,j,k; 17 cin>>a>>b>>n; 18 logn=log2(n); 19 for (i=1;i<=a;i++) 20 { 21 for (j=1;j<=b;j++) 22 scanf("%d",&f1[i][j]),f2[i][j]=f1[i][j]; 23 } 24 for (k=0;k<logn;k++) 25 { 26 for (i=1;i+(1<<k)<=a;i++) 27 { 28 for (j=1;j+(1<<k)<=b;j++) 29 { 30 f1[i][j]=max(f1[i][j],max(f1[i+(1<<k)][j],max(f1[i][j+(1<<k)],f1[i+(1<<k)][j+(1<<k)]))); 31 f2[i][j]=min(f2[i][j],min(f2[i+(1<<k)][j],min(f2[i][j+(1<<k)],f2[i+(1<<k)][j+(1<<k)]))); 32 } 33 } 34 } 35 ans=2e9; 36 for (i=1;i<=a-n+1;i++) 37 for (j=1;j<=b-n+1;j++) 38 ans=min(ans,query(i,j)); 39 cout<<ans; 40 }
以上是关于[HAOI2007]理想的正方形的主要内容,如果未能解决你的问题,请参考以下文章