zoukankan      html  css  js  c++  java
  • 【简●解】[HAOI2007] 理想的正方形

    【题目大意】

    有一个(a*b)的整数组成的矩阵,现请你从中找出一个(n*n)的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

    【分析】

    在暴力中想到优化,模仿曾经求二维前缀和的做法,先在每行求区间长度为(n)的最大值和最小值,再在此基础上求列上的最大值和最小值,则求得的即为单个(n*n)正方形矩阵中的最大值和最小值。(仔细体味下)

    用单调队列就可以搞定,和滑动窗口类似。

    【Code】

    一个挣扎在英语一线的苦逼(Oier)。。。敲代码背单词。。。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N = 1000 + 5;
    const int INF = 0x7fffffff;
    inline int read(){
    	int f = 1, x = 0;char ch;
    	do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0'||ch>'9');
    	do {x = x*10+ch-'0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); 
    	return f*x;
    }
    int a, b, n, aa, bb, maps[N][N], ans = INF;
    int shallow[N][N];// 肤浅的 adj. ---X最大值 
    int reform[N][N];// 改革,改进 v. ---X最小值 
    int allergic[N][N];// 敏感的 adj. ---Y最大值
    int association[N][N];//协会,交往 n. ---Y最小值 
    int violence[20 * N];// 暴力行为 adj. ---队列 
    int head = 1, tail = 0;
    
    int main(){
    	a = read(), b = read(), n = read();
    	for (int i = 1;i <= a; ++i) {
    		for (int j = 1;j <= b; ++j) {
    			maps[i][j] = read();
    		}
    	}
    	aa = a - n + 1;
    	bb = b - n + 1;
    	
    	for (int i = 1;i <= a; ++i) {
    		head = 1, tail = 0;
    //		printf("rand %d : %d - %d 
    ", i, head, tail) ;		
    		for (int j = 1;j <= b; ++j) {
    			while (maps[i][violence[tail]] <= maps[i][j] && head <= tail) tail--;
    			violence[++tail] = j;			
    			while (head <= tail && violence[head] < j - n + 1) {
    				head++;
    			}
    			shallow[i][j] = maps[i][violence[head]];
    		}
    	}
    	
    	for (int i = 1;i <= a; ++i) {
    		head = 1, tail = 0;
    //		printf("rand %d : %d - %d 
    ", i, head, tail) ;		
    		for (int j = 1;j <= b; ++j) {
    			while (maps[i][violence[tail]] >= maps[i][j] && head <= tail) tail--;
    			violence[++tail] = j;			
    			while (head <= tail && violence[head] < j - n + 1) {
    				head++;
    			}
    			reform[i][j] = maps[i][violence[head]];
    		}
    	}
    
    //	puts("");
    //	for (int i = 1;i <= a; ++i) {
    //		for (int j = 1; j <= b; ++j) {
    //			printf("%d ", reform[i][j]);
    //		}
    //		puts("");
    //	}	
    	
    	for (int j = 1;j <= b; ++j) {
    		head = 1, tail = 0;
    		for (int i = 1;i <= a; ++i) {
    			while (shallow[violence[tail]][j] <= shallow[i][j] && head <= tail) tail--;
    			violence[++tail] = i;			
    			while (head <= tail && violence[head] < i - n + 1) {
    				head++;
    			}
    			allergic[i][j] = shallow[violence[head]][j];
    		}
    	}
    
    //	puts("");
    //	for (int i = 1;i <= a; ++i) {
    //		for (int j = 1; j <= b; ++j) {
    //			printf("%d ", allergic[i][j]);
    //		}
    //		puts("");
    //	}	
    	
    	for (int j = 1;j <= b; ++j) {
    		head = 1, tail = 0;
    		for (int i = 1;i <= a; ++i) {
    			while (reform[violence[tail]][j] >= reform[i][j] && head <= tail) tail--;
    			violence[++tail] = i;			
    			while (head <= tail && violence[head] < i - n + 1) {
    				head++;
    			}
    			association[i][j] = reform[violence[head]][j];			
    		}
    	}
    
    //	puts("");
    //	for (int i = 1;i <= a; ++i) {
    //		for (int j = 1; j <= b; ++j) {
    //			printf("%d ", association[i][j]);
    //		}
    //		puts("");
    //	}	
    	
    	for (int i = n; i <= a; ++i) {
    		for (int j = n; j <= b; ++j) {
    			ans = min(ans, allergic[i][j] - association[i][j]);
    		}
    	}
    	
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    面试题58 二叉树的下一个结点
    面试题57 删除链表中重复的结点
    面试题56 链表中环的入口结点
    面试题55 字符流中第一个不重复的字符
    面试题54 表示数值的字符串
    面试题50 树中两个结点的最低公共祖先
    面试题53 正则表达式匹配
    面试题52 构建乘积数组
    面试题51 数组中重复的数字
    Qt链接库出错version Qt_5 not defined
  • 原文地址:https://www.cnblogs.com/silentEAG/p/10901847.html
Copyright © 2011-2022 走看看