【DP专题】——洛谷P2216理想正方形

强烈推荐这道单调队列好题!

传送门:GO


参考了一下这篇题解:GO

对于点(i,j)

两个单调队列,先以行为单位,求出长度为n的一段区间的最值(i,(j~j+n-1)),在此基础上,以列为单位,求出((i~i+n-1),(j~j+n-1))的最值。

以n为3为例:

 先是这样的感觉,每个色条处理的是每块的最值。

 接着根据上面求出的结果,竖着来一次。

最后就能得到每个点为左上角的n*n正方形的最值了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int read(){
 4     int x=0,f=1;
 5     char c=getchar();
 6     while(!isdigit(c)){
 7         if(c=='-') f=-1;
 8         c=getchar();
 9     }
10     while(isdigit(c)){
11         x=(x<<1)+(x<<3)+(c^48);
12         c=getchar();
13     }
14     return x*f;
15 }
16 const int N=1e3+10;
17 int a,b,n;
18 int ma[N][N];
19 int maxwh[N][N],maxn[N][N],minwh[N][N],minn[N][N];
20 int que1[N<<1],que2[N<<1];
21 int head1,tail1,head2,tail2;
22 int main(){
23     a=read();b=read();n=read();
24     for(int i=1;i<=a;i++){
25         for(int j=1;j<=b;j++){
26             ma[i][j]=read();
27         }
28     }
29     for(int i=1;i<=a;i++){
30         head1=tail1=head2=tail2=que1[1]=que2[1]=1;
31         for(int j=2;j<=b;j++){
32             while(head1<=tail1&&ma[i][j]>=ma[i][que1[tail1]]) tail1--;
33             while(head2<=tail2&&ma[i][j]<=ma[i][que2[tail2]]) tail2--;
34             que1[++tail1]=j;
35             que2[++tail2]=j;
36             while(j-que1[head1]+1>n) head1++;
37             while(j-que2[head2]+1>n) head2++;
38             if(j>=n) maxwh[i][j-n+1]=ma[i][que1[head1]],minwh[i][j-n+1]=ma[i][que2[head2]]; 
39         }
40     }
41     for(int i=1;i<=b-n+1;i++){
42         head1=tail1=head2=tail2=que1[1]=que2[1]=1;
43         for(int j=2;j<=a;j++){
44             while(head1<=tail1&&maxwh[j][i]>=maxwh[que1[tail1]][i]) tail1--;
45             while(head2<=tail2&&minwh[j][i]<=minwh[que2[tail2]][i]) tail2--;
46             que1[++tail1]=j;
47             que2[++tail2]=j;
48             while(j-que1[head1]+1>n) head1++;
49             while(j-que2[head2]+1>n) head2++;
50             if(j>=n) maxn[j-n+1][i]=maxwh[que1[head1]][i],minn[j-n+1][i]=minwh[que2[head2]][i];
51         }
52     }
53     int ans=1e9;
54     for(int i=1;i<=a-n+1;i++){
55         for(int j=1;j<=b-n+1;j++){
56             ans=min(ans,maxn[i][j]-minn[i][j]);
57         }
58     }
59     printf("%d",ans);
60     return 0;
61 } 
——抓住了时间,却不会利用的人,终究也逃不过失败的命运。
原文地址:https://www.cnblogs.com/Nelson992770019/p/11599899.html