Topic link: https://ac.nowcoder.com/acm/contest/883/F
Idea: Enumerate the upper and lower boundaries, as well as the right boundaries. So, when we know the upper and lower boundaries, how to calculate the maximum matrix quickly? Notice that when we enumerate the right boundaries, we are from left to right. When we know the number of left boundaries, we need to find ways to make full use of this information. Assuming that we know the maximum and minimum values of each column, we can use two monotone queues to maintain the minimum, maximum and minimum respectively. The small value increases and the maximum decreases. Then, when judging whether the interval is legitimate, we only need to take out the maximum and minimum of the team head to judge. So how to quickly know the maximum value of each column for a fixed upper and lower boundary? Similarly, when the lower boundaries are increased by one line at a time, we can update the maximum information at that time.
OK then is to write the code, because the two queues of the first element of the position is not equal, wa many times, and then read the code of others, change the location of the same, too.
#include<iostream> using namespace std; const int N = 510; int a[N][N]; int n,m; int mx[N],mi[N]; void init(){ for(int i=1;i<=n;i++)mx[i]=-1e6,mi[i]=1e6; } struct{ int s,t; int id[N]; void init(){ t=0;s=1; } void PUSH(int x,int type){ if(type==1){ while(s<=t&&mx[x]>mx[id[t]])t--; id[++t]=x; } else{ while(s<=t&&mi[x]<mi[id[t]])t--; id[++t]=x; } } void POP(){ s++; } int BACK(int type){ if(type)return mx[id[s]]; else return mi[id[s]]; } int ID(){ return id[s]; } bool Empty(){return s<=t;} void pri(){ for(int i=s;i<=t;i++)cout<<mx[id[i]]<<"ll "; cout<<endl; } }MAX,MIN; int main(){ int t ; scanf("%d",&t); while(t--){ int ans=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",a[i]+j); for(int up=1;up<=n;up++){ init(); for(int down=up;down<=n;down++){ for(int i=1;i<=n;i++){ mi[i]=min(a[down][i],mi[i]); mx[i]=max(mx[i],a[down][i]); } MAX.init(); MIN.init(); int R=0; int L=1; while(R<=n){ if(R-L+1==0||MAX.BACK(1)-MIN.BACK(0)<=m){ ans=max(ans,(down-up+1)*(R-L+1)); R++; MAX.PUSH(R,1); MIN.PUSH(R,0); } else{ if(MAX.ID()==L)MAX.POP(); if(MIN.ID()==L)MIN.POP(); L++; } } } } printf("%d\n",ans); } return 0; }
Error code:
#include<iostream> using namespace std; const int N = 510; int a[N][N]; int n,m; int mx[N],mi[N]; void init(){ for(int i=1;i<=n;i++)mx[i]=-1e6,mi[i]=1e6; } struct{ int s,t; int id[N]; void init(){ t=0;s=1; } void PUSH(int x,int type){ if(type==1){ while(s<=t&&mx[x]>mx[id[t]])t--; id[++t]=x; } else{ while(s<=t&&mi[x]<mi[id[t]])t--; id[++t]=x; } } void POP(){ s++; } int BACK(int type){ if(type)return mx[id[s]]; else return mi[id[s]]; } int ID(){ return id[s]; } bool Empty(){return s<=t;} void pri(){ for(int i=s;i<=t;i++)cout<<mx[id[i]]<<"ll "; cout<<endl; } }MAX,MIN; int main(){ int t ; scanf("%d",&t); while(t--){ int ans=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",a[i]+j); for(int up=1;up<=n;up++){ init(); for(int down=up;down<=n;down++){ for(int i=1;i<=n;i++){ mi[i]=min(a[down][i],mi[i]); mx[i]=max(mx[i],a[down][i]); } MAX.init(); MIN.init(); for(int R=1;R<=n;R++){ MAX.PUSH(R,1); MIN.PUSH(R,0); // MAX.pri(); // cout<<"____________\n"; while(MAX.Empty()&&MIN.Empty()&&MAX.BACK(1)-MIN.BACK(0)>m){ if(MAX.ID()>MIN.ID())MIN.POP(); else if(MAX.ID()<MIN.ID())MAX.POP(); else{ MAX.POP(); MIN.POP(); } } if(MAX.Empty()&&MIN.Empty()){ ans=max(ans,(down-up+1)*(R+1-max(MAX.ID(),MIN.ID()))); // cout<<up<<" "<<down<<" "<<max(MAX.ID(),MIN.ID())<<" "<<R<<"pl \n"; } } } } printf("%d\n",ans); } return 0; }