【2019牛客暑期多校训练营(第三场)- F】Planting Trees(单调队列,尺取)
題干:
鏈接:https://ac.nowcoder.com/acm/contest/883/F
來源:牛客網
?
The semester is finally over and the summer holiday is coming. However, as part of your university's graduation requirement, you have to take part in some social service during the holiday. Eventually, you decided to join a volunteer group which will plant trees in a mountain.
?
To simplify the problem, let's represent the mountain where trees are to be planted with an N×NN \times NN×N grid. Let's number the rows?1\ 1?1 to?N\ N?N from top to bottom, and number the columns?1\ 1?1 to?N\ N?N from left to right. The elevation of the cell in the?i\ i?i-th row and?j\ j?j-th column is denoted by ai,ja_{i,j}ai,j?. Your leader decides that trees should be planted in a rectangular area within the mountain and that the maximum difference in elevation among the cells in that rectangle should not exceed M. In other words, if the coordinates of the top-left and the bottom-right corners of the rectangle are (x1,y1)(x_1,y_1)(x1?,y1?) and (x2,y2)(x_2,y_2)(x2?,y2?), then the condition ∣ai,j?ak,l∣≤M|a_{i,j} - a_{k,l}| \le M∣ai,j??ak,l?∣≤M must hold for x1≤i,k≤x2,?y1≤j,l≤y2x_1 \le i,k \le x_2, \ y_1 \le j,l \le y_2x1?≤i,k≤x2?,?y1?≤j,l≤y2?. Please help your leader calculate the maximum possible number of cells in such a rectangle so that he'll know how many trees will be planted.
輸入描述:
The input contains multiple cases. The first line of the input contains a single integer T?(1≤T≤1000)T \ (1 \le T \le 1000)T?(1≤T≤1000), the number of cases. For each case, the first line of the input contains two integers N?(1≤N≤500)N\ (1 \le N \le 500)N?(1≤N≤500) and M?(0≤M≤105)M\ (0 \le M \le 10^5)M?(0≤M≤105). The following N lines each contain N integers, where the?j\ j?j-th integer in the?i\ i?i-th line denotes ai,j?(1≤ai,j≤105)a_{i,j} \ (1 \le a_{i,j} \le 10^5)ai,j??(1≤ai,j?≤105). It is guaranteed that the sum of N3N^3N3 over all cases does not exceed 25?10725 \cdot 10^725?107.輸出描述:
For each case, print a single integer, the maximum number of cells in a valid rectangle.示例1
輸入
復制
2 2 0 1 2 2 1 3 1 1 3 2 2 3 1 3 2 1輸出
復制
1 4題目大意:
給一個N*N矩陣(N<=500,且保證所有樣例的,時限3秒)
找出最大的矩陣滿足其中最大值和最小值的差小于等于M,讓你輸出的是這個可能的最大差值。
解題報告:
既然給你了N和時限這么清楚肯定就是讓你找一個N^3的做法而不能帶log。
首先枚舉兩行,然后剩下一個N用在求這一段中的最大最小值。
那么比較容易想到的就是二分長度然后拿個st表或者什么之類的掃一遍但是這樣肯定帶個log。
考慮尺取,這樣需要在O1時間內求出當前窗口的最大值和最小值的差,選擇單調隊列。
但是這題用STL會被卡,,所以手寫一波就OK了。
注意數組不是維護的前綴和,而是前綴最大值和前綴最小值。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 500 + 5; int a[MAX][MAX],M,NUM[MAX],num[MAX]; int n; int ans; int qmin[555],qmax[555],f,b,F,B; int main() {int t;scanf("%d",&t);while(t--) {scanf("%d%d",&n,&M);ans=0;for(int i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) {scanf("%d",&a[i][j]);}}for(int u = 1; u<=n; u++) {for(int i = 1; i<=n; i++) num[i]=NUM[i]=a[u][i];for(int d = u; d<=n; d++) {for(int i = 1; i<=n; i++) num[i] = min(num[i],a[d][i]),NUM[i] = max(NUM[i],a[d][i]); // deque<int> qmin; deque<int> qmax;f=F=1;b=B=1;int i = 1, j = 1;while(i <= n) {if(i > j) j = i;while(j <= n) {while(f < b && num[qmin[b-1]] >= num[j]) b--;qmin[b++]=j;while(F < B && NUM[qmax[B-1]] <= NUM[j]) B--;qmax[B++]=j;if(NUM[qmax[F]] - num[qmin[f]] > M) break;j++;}if(qmin[f] == i) f++;if(qmax[F] == i) F++;ans = max(ans,(j-i)*(d-u+1));i++;}}}printf("%d\n",ans);}return 0 ; }最近又重寫了一個優先移動右端點的版本:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define FF first #define SS second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 500 + 5; struct Deque {int a[MAX];int f,b;//f是隊首 b是隊尾Deque() {f=b=0;}void clear() {f=b=0;}bool empty() {return f==b;}void pop_back() {b--;}void pop_front(){f++;}void push_back(int x){a[b++] = x;}int back() {return a[b-1];}int front() {return a[f];} }Max,Min; int a[MAX][MAX],sum[MAX],SUM[MAX]; int n,M; int main() {int t;cin>>t;while(t--) {int ans = 0;Max.clear(),Min.clear();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++) {for(int j = 1; j<=n; j++) sum[j] = SUM[j] = a[up][j];for(int down = up; down<=n; down++) {for(int j = 1; j<=n; j++) sum[j] = min(sum[j],a[down][j]),SUM[j] = max(SUM[j],a[down][j]);//預處理當前要用的sum和SUM數組int l = 1;Max.clear();Min.clear();for(int r = 1; r<=n; r++) {while(!Max.empty() && SUM[Max.back()] <= SUM[r]) Max.pop_back();Max.push_back(r);while(!Min.empty() && sum[Min.back()] >= sum[r]) Min.pop_back();Min.push_back(r);while(l<=r && SUM[Max.front()] - sum[Min.front()] > M) {if(Max.front() == l) Max.pop_front();if(Min.front() == l) Min.pop_front();l++;}ans = max(ans,(down-up+1) * (r-l+1));}}}printf("%d\n",ans);}return 0 ; }?
總結
以上是生活随笔為你收集整理的【2019牛客暑期多校训练营(第三场)- F】Planting Trees(单调队列,尺取)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡审核要多久 各银行信用卡审核时间一
- 下一篇: 建行信用卡额度一般是多少 几招技巧让你额