HAOI2007 理想的正方形 单调队列

单调队列

 

by   GeneralLiu

 

滑动窗口是比较裸的单调队列

理想的正方形   就拔高了一个层次(多了一维)

有一个a*b的整数组成的矩阵

现请你从中找出一个n*n的正方形区域

使得该区域所有数中的最大值和最小值的差最小

 

只写MAX了,MIN一个道理,懒 不写了

先横着跑单调队列

  维护许多长度为 n 的 横着的MAX

  存在数组 map1[][] 中

再对数组 map1[][] 竖着跑单调队列

  就维护了 许多 n*n 的 矩阵的MAX

MIN同理

在竖着跑单调队列时

顺便MAX 与 MIN 作差

更新答案即可

 

代码

 

一个小地方debug了好久

代码上还有 

学 mzx dalao  “ 二分出错位置  输出中间答案 ” 的 “ 蛛丝马迹 ”

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define A 1005
  4 #define N 105
  5 int an=1000000001,h2,t2,h1,t1,a,b,n;
  6 int pos1[A],pos2[A],que1[A],que2[A];
  7 int mip1[A][A],map1[A][A];
  8 int mip2[A][A],map2[A][A];
  9 int read(){  //  读入优化 
 10     int ans=0;
 11     char ch=getchar();
 12     for(;!isdigit(ch);ch=getchar());
 13     for(;isdigit(ch);ch=getchar())
 14         ans=ans*10+ch-'0';
 15     return ans;
 16 }
 17 int main(){
 18     a=read(),b=read(),n=read();
 19     for(int k,i=1;i<=a;i++){
 20         h1=h2=1;
 21         t1=t2=0;
 22         for(int j=1;j<=b;j++){
 23             k=read();
 24             
 25             for(;t1>=h1&&k>=que1[t1];t1--);
 26             que1[++t1]=k;
 27             pos1[t1]=j;
 28             
 29             for(;t2>=h2&&k<=que2[t2];t2--);
 30             que2[++t2]=k;
 31             pos2[t2]=j;
 32             
 33             if(j>=n){
 34                 map1[i][j]=que1[h1];
 35                 mip1[i][j]=que2[h2];
 36                 if(pos1[h1]==j-n+1)h1++;
 37                 if(pos2[h2]==j-n+1)h2++;
 38             }
 39         }
 40     }
 41     /*cout<<endl;
 42     for(int i=1;i<=a;i++){
 43       for(int j=1;j<=b;j++)
 44         cout<<map1[i][j]<<" ";
 45       cout<<endl;
 46     }
 47     cout<<endl;
 48     for(int i=1;i<=a;i++){
 49       for(int j=1;j<=b;j++)
 50         cout<<mip1[i][j]<<" ";
 51       cout<<endl;
 52     }
 53     cout<<endl;*/
 54     for(int k1,k2,i=n;i<=b;i++){
 55         h1=h2=1;
 56         t1=t2=0;
 57         for(int j=1;j<=a;j++){
 58             k1=map1[j][i];
 59             k2=mip1[j][i];
 60             
 61             for(;t1>=h1&&k1>=que1[t1];t1--);
 62             que1[++t1]=k1;
 63             pos1[t1]=j;
 64             
 65             for(;t2>=h2&&k2<=que2[t2];t2--);
 66             que2[++t2]=k2;
 67             pos2[t2]=j;
 68             
 69             
 70             if(j>=n){
 71               //map2[j][i]=que1[h1];
 72               //mip2[j][i]=que2[h2];
 73               an=min(an,que1[h1]-que2[h2]);
 74               if(pos1[h1]==j-n+1)h1++;
 75               if(pos2[h2]==j-n+1)h2++;
 76             }
 77         }
 78     }
 79     
 80     /*for(int i=1;i<=a;i++){
 81       for(int j=1;j<=b;j++)
 82         cout<<map2[i][j]<<" ";
 83       cout<<endl;
 84     }
 85     cout<<endl;
 86     for(int i=1;i<=a;i++){
 87       for(int j=1;j<=b;j++)
 88         cout<<mip2[i][j]<<" ";
 89       cout<<endl;
 90     }
 91     cout<<endl;*/
 92     
 93     cout<<an;
 94     
 95     return 0;
 96 }/*5 4 2 
 97 1 2 5 6 
 98 0 17 16 0 
 99 16 17 0 1 
100 2 10 2 1 
101 1 2 3 2
102 
103 2
104 */

 

转载于:https://www.cnblogs.com/1227xq/p/6794595.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值