洛谷P2216 [HAOI2007]理想的正方形
? 解题记录 ? ? 洛谷 ? ? ST表 ?    2017-10-14 22:57:24    455    0    0

题目描述

有一个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表。st[i][j][k][2]表示i,j向右下方2^k内最大的数和最小的数,就可以每一次从前四块递推了!时间复杂度O(N^2 log N)就是查询有点蛋疼。但是光是这样是得不全分的只有60,经过了一波骚操作常数优化才能得到80分。

就在我快要弃疗的时候,我瞬间就想起了fread()快速读入优化。然后随便一交……WOC,竟然A了。看来getchar已经跟不上时代了啊。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define MX 0
#define MN 1
using namespace std;
const int maxn = 1e3 + 5;
const int max2 = 12;
int pow2[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096};
int st[maxn][maxn][max2][2], dt, k, n, m, mn, tmp, tmp1, tmp2, turn; 
char c;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int & x) {
    x = 0;c = gc();
    while(c > '9' || c < '0') c = gc();
    while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + c - '0', c = gc();
}
void st2d(int n, int m) {
	tmp = log2(k);
    turn = log2(k - 1);
    for(register int k = 1; k <= tmp; ++k)
        for(register int i = 1; i <= m - pow2[k] + 1; ++i)
               for(register int j = 1; j <= n - pow2[k] + 1; ++j) {
                   st[j][i][k][MN] = min(min(st[j][i][k - 1][MN], st[j + pow2[k - 1]][i + pow2[k - 1]][k - 1][MN]), min(st[j + pow2[k - 1]][i][k - 1][MN], st[j][i + pow2[k - 1]][k - 1][MN]));
                   st[j][i][k][MX] = max(max(st[j][i][k - 1][MX], st[j + pow2[k - 1]][i + pow2[k - 1]][k - 1][MX]), max(st[j + pow2[k - 1]][i][k - 1][MX], st[j][i + pow2[k - 1]][k - 1][MX]));
               }
}
int qMX(int x, int y, int n) {
	tmp = pow2[turn];
    tmp1 = max(st[x][y][turn][MX], st[x + n - tmp][y + n - tmp][turn][MX]);
    tmp2 = max(st[x + n - tmp][y][turn][MX], st[x][y + n - tmp][turn][MX]);
    return max(tmp1, tmp2);
}
int qMN(int x, int y, int n) {
	tmp = pow2[turn];
    tmp1 = min(st[x][y][turn][MN], st[x + n - tmp][y + n - tmp][turn][MN]);
    tmp2 = min(st[x + n - tmp][y][turn][MN], st[x][y + n - tmp][turn][MN]);
    return min(tmp1, tmp2);
}
int main() {
    read(n), read(m), read(k);
    mn = 0x7fffffff;
    for(register int i = 1; i <= n; ++i)
        for(register int j = 1; j <= m; ++j)
            read(st[i][j][0][MX]), st[i][j][0][MN] = st[i][j][0][MX];
    st2d(n, m);
    for(register int i = 1; i <= n - k + 1; ++i)
        for(register int j = 1; j <= m - k + 1; ++j) {
            dt = qMX(i, j, k) - qMN(i, j, k);
            if(dt < mn) 
                mn = dt;
        }
    printf("%d", mn);
    return 0;
}

 

上一篇: 洛谷P2331 [SCOI2005]最大子矩阵

下一篇: 洛谷P1880 石子合并

455 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航