References:
Algorithm Introduction
Monotonic queue can be done in O ( n ) O(n)In the time complexity of O ( n ) , find the length of nnIn a sequence of n , each length ismmThe maximum value of the interval of m .
algorithm thinking
Visual understanding: In each cycle, first check whether the "senior" at the head of the team has graduated , then kick out all the seniors who are inferior to the "freshmen" in the queue, and finally let the freshmen join the team.
The specific algorithm idea can be found in reference materials.
Example 1 P2216 [HAOI2007] ideal square
topic description
There is a × ba \times ba×A matrix composed of integers of b , now please find an × nn \times nn×A square region of n such that the difference between the maximum and minimum values of all numbers in the region is minimized.
input format
First line 3 33 integers, respectively representinga, b, na, b, na,b,The value of n .
The second row to the first a + 1 a+1a+1 line for each linebbb non-negative integers, representing the number at the corresponding position in the matrix. Each row is separated by a space between two adjacent numbers.
output format
Only one integer, for a × ba \times ba×All n × nn \times nin the b matrixn×The minimum value of the difference between the largest integer and the smallest integer in an n square area".
Example #1
Sample Input #1
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample output #1
1
hint
All numbers in the matrix do not exceed 1 , 000 , 000 , 000 1,000,000,0001,000,000,000。
100 % 100\% 100% confidence2≤ a , b ≤ 1000 , n ≤ a , n ≤ b , n ≤ 100 2 \and a,b \and 1000,n \and a,n \and b,n \and2≤a,b≤1000,n≤a,n≤b,n≤100。
train of thought
General idea: use a monotone queue to find each n × nn\times nn×The maximum and minimum values of n squares, and then traverse each square to update the answer.
Take finding the maximum value within a square as an example. First scan each row of the input matrix, and find the length of each row is nnThe maximum value of the interval of nmmax[][]
, stored in the matrix . Then scanmmax[][]
each legal column in and find each lengthnnThe maximum value of the interval of nmmmax[][]
, stored in the matrix .
the code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int a, b, n;
int mtx[maxn][maxn];
int mmax[maxn][maxn];
int mmmax[maxn][maxn];
int mmin[maxn][maxn];
int mmmin[maxn][maxn];
int ans = 0x7fffffff;
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>a>>b>>n;
for(int i=1;i<=a;i++){
for(int j=1;j<=b;j++){
cin>>mtx[i][j];
}
}
// 求正方形内最大值
for(int i=1;i<=a;i++){
deque<int> q;
for(int j=1;j<=b;j++){
if(!q.empty() && j-q.front()+1>n) q.pop_front();
while(!q.empty() && mtx[i][j]>mtx[i][q.back()]) q.pop_back();
q.push_back(j);
if(j>=n){
mmax[i][j] = mtx[i][q.front()];
}
}
}
for(int j=n;j<=b;j++){
deque<int> q;
for(int i=1;i<=a;i++){
if(!q.empty() && i-q.front()+1>n) q.pop_front();
while(!q.empty() && mmax[i][j]>mmax[q.back()][j]) q.pop_back();
q.push_back(i);
if(i>=n){
mmmax[i][j] = mmax[q.front()][j];
}
}
}
// 求正方形内最小值
for(int i=1;i<=a;i++){
deque<int> q;
for(int j=1;j<=b;j++){
if(!q.empty() && j-q.front()+1>n) q.pop_front();
while(!q.empty() && mtx[i][j]<mtx[i][q.back()]) q.pop_back();
q.push_back(j);
if(j>=n){
mmin[i][j] = mtx[i][q.front()];
}
}
}
for(int j=n;j<=b;j++){
deque<int> q;
for(int i=1;i<=a;i++){
if(!q.empty() && i-q.front()+1>n) q.pop_front();
while(!q.empty() && mmin[i][j]<mmin[q.back()][j]) q.pop_back();
q.push_back(i);
if(i>=n){
mmmin[i][j] = mmin[q.front()][j];
}
}
}
// 求最终答案
for(int i=n;i<=a;i++){
for(int j=n;j<=b;j++){
ans = min(ans, mmmax[i][j]-mmmin[i][j]);
}
}
cout<<ans;
return 0;
}
Example 2 P2034 select number
topic description
Given a row of nnn non-negative integersa 1 ⋯ an a_1 \cdots a_na1⋯an. Now you can choose some of them, but there cannot be more than kkk consecutive numbers are selected. Your task is to maximize the sum of the selected numbers.
input format
The first line of two integers nnn, k k k。
following nnn lines, one integer per line representsai a_iai。
output format
Output a value representing the answer.
Example #1
Sample Input #1
5 2
1
2
3
4
5
Sample output #1
12
hint
For 100 % 100\%100% of the data,1 ≤ n ≤ 100000 1 \le n \le 1000001≤n≤100000,1 ≤ k≤ n 1 \le k \le n1≤k≤n,0 ≤ 0 \le0≤ number size≤ 1 , 000 , 000 , 000 \le 1,000,000,000≤1,000,000,000。
train of thought
This question is a classic example of dynamic programming for monotonic queue optimization .
Convert the topic to: delete several numbers from the topic, and the difference between the serial numbers of any two deleted numbers is less than or equal to k
. Under the premise of meeting the requirements of the topic, the sum of the deleted numbers should be as small as possible.
Defining the state dp[i]
means: Considering only the first i
number and deleting the first i
number, the smallest sum to be deleted. The state transition equation is:
dp [ i ] = { a [ i ] , i ≤ k + 1 a [ i ] + min i − k − 1 ≤ j ≤ i − 1 dp [ j ] , i > k + 1 dp [i] = \begin{cases} a[i],\ i\leq k+1\\ a[i]+\min\limits_{ik-1 \leq j\leq i-1} dp[j], \i>k+1 \end{cases}dp[i]=⎩
⎨
⎧a[i], i≤k+1a[i]+i−k−1≤j≤i−1mindp[j], i>k+1
It can be seen that the state transition needs to use the maximum value of the fixed-length interval , so monotonic queue optimization can be used.
the code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5+5;
int n, k;
int a[maxn];
int dp[maxn];
int sum = 0;
int ans = 0x7fffffff;
deque<int> q;
signed main(){
cin>>n>>k;
k += 1;
for(int i=1;i<=n;i++){
cin>>a[i];
sum += a[i];
}
for(int i=1;i<=n;i++){
if(!q.empty() && i>k) dp[i] += dp[q.front()];
dp[i] += a[i];
if(!q.empty() && i-q.front()+1>k) q.pop_front();
while(!q.empty() && dp[i]<dp[q.back()]) q.pop_back();
q.push_back(i);
}
ans = sum;
for(int i=n-k+1;i<=n;i++){
ans = min(ans, dp[i]);
}
cout<<sum-ans;
return 0;
}
Example 3 P2698 [USACO12MAR] Flowerpot S
topic description
The boss needs your help watering the flowers. gives NNCoordinates of N drops of water, yyy represents the height of the droplet,xxx means it falls toxxThe position of the x- axis.
1 per second per dropFalling at a speed of 1 unit length. You need to place the flower pot atxxA certain position on the x- axis makes the 1st11 drop of water starts, to the last1 11 drop ends with a time difference of at leastDDD。
We believe that as long as the water drop reaches xxOn the x- axis, it is considered to be caught if it is aligned with the edge of the flowerpot. givesNNCoordinates of N drops andDDFor the size of D , please calculate the width WWof the smallest flower potW。
input format
first line 2 22 integersNNN andDDD。
Next NNN lines each line2 22 integers, representing the coordinates of the water drop( x , y ) (x,y)(x,y)。
output format
Only one row 1 11 integer, indicating the width of the smallest flowerpot. If it is not possible to construct a pot wide enough thatthe DDD units of time to catch the water droplets that meet the requirements, then output− 1 -1−1。
Example #1
Sample Input #1
4 5
6 3
2 4
4 10
12 15
Sample output #1
2
hint
100 % 100\% 100% of data:1 ≤ N ≤ 1 0 5 1 \le N \le 10 ^ 51≤N≤105,1 ≤ D ≤ 1 0 6 1 \le D \le 10 ^ 61≤D≤106,0 ≤ x , y ≤ 1 0 6 0\le x,y\le10^60≤x,y≤106 。
train of thought
Binary answer + monotonic queue
It should be noted that the condition for the head of the team to leave the team is: the xx of the current water drop and the water drop at the head of the teamThe difference in x coordinatesis greater than the pot width.
the code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
struct NODE{
int x, y;
bool operator<(const NODE& a)const{
if(x==a.x) return y<a.y;
else return x<a.x;
}
};
NODE node[maxn];
int n, d;
int m = 0x7fffffff, M = -1;
int L = 0x7fffffff, R = -1;
int ans = 0x7fffffff;
bool check(int len){
deque<int> q1, q2;
for(int i=1;i<=n;i++){
if(!q1.empty() && node[i].x-node[q1.front()].x>len) q1.pop_front();
if(!q2.empty() && node[i].x-node[q2.front()].x>len) q2.pop_front();
while(!q1.empty() && node[i].y>node[q1.back()].y) q1.pop_back();
while(!q2.empty() && node[i].y<node[q2.back()].y) q2.pop_back();
q1.push_back(i);
q2.push_back(i);
if(node[q1.front()].y-node[q2.front()].y >= d) return true;
}
return false;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>n>>d;
for(int i=1;i<=n;i++){
cin>>node[i].x>>node[i].y;
m = min(m, node[i].y);
M = max(M, node[i].y);
L = min(L, node[i].x);
R = max(R, node[i].x);
}
sort(node+1, node+1+n);
R = R-L, L = 0;
if(M-m<d){
cout<<-1;
return 0;
}
while(L <= R){
int mid = (L+R)>>1;
if(check(mid)){
ans = min(ans, mid);
R = mid-1;
}
else{
L = mid+1;
}
}
cout<<ans;
return 0;
}