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;
    }
    
  • 相关阅读:
    MyBatis 处理sql中的 大于,小于,大于等于,小于等于
    以当前日期为时间轴 计算15 天的日期 和15 天后的日期
    java 常用时间操作类,计算到期提醒,N年后,N月后的日期
    用户号已经存在是否覆盖解决办
    List<bean> 转换成List<Map>
    feig中调用其他微服务接口无反应
    从实体类中取值 ,获取修改记录信息,保存修改记录信息
    java遍历实体类的属性和值
    从数据库将数据导出到excel表格
    树同构模板
  • 原文地址:https://www.cnblogs.com/silentEAG/p/10901847.html
Copyright © 2011-2022 走看看