P3572 [POI2014]PTA-Little Bird(单调队列DP)
题目描述
In the Byteotian Line Forest there are nn trees in a row.
On top of the first one, there is a little bird who would like to fly over to the top of the last tree.
Being in fact very little, the bird might lack the strength to fly there without any stop.
If the bird is sitting on top of the tree no. i, then in a single flight leg it can fly toany of the trees no. i+1,i+2,\cdots,i+ki+1,i+2,⋯,i+k, and then has to rest afterward.
Moreover, flying up is far harder to flying down. A flight leg is tiresome if it ends in a tree at leastas high as the one where is started. Otherwise the flight leg is not tiresome.
The goal is to select the trees on which the little bird will land so that the overall flight is leasttiresome, i.e., it has the minimum number of tiresome legs.
We note that birds are social creatures, and our bird has a few bird-friends who would also like to getfrom the first tree to the last one. The stamina of all the birds varies,so the bird's friends may have different values of the parameter kk.
Help all the birds, little and big!
从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力
输入格式
There is a single integer nn (2\le n\le 1\ 000\ 0002≤n≤1 000 000) in the first line of the standard input:
the number of trees in the Byteotian Line Forest.
The second line of input holds nn integers d_1,d_2,\cdots,d_nd1,d2,⋯,dn (1\le d_i\le 10^91≤di≤109)separated by single spaces: d_idi is the height of the i-th tree.
The third line of the input holds a single integer qq (1\le q\le 251≤q≤25): the number of birds whoseflights need to be planned.
The following qq lines describe these birds: in the ii-th of these lines, there is an integer k_iki (1\le k_i\le n-11≤ki≤n−1) specifying the ii-th bird's stamina. In other words, the maximum number of trees that the ii-th bird can pass before it has to rest is k_i-1ki−1.
输出格式
Your program should print exactly qq lines to the standard output.
In the ii-th line, it should specify the minimum number of tiresome flight legs of the ii-th bird.
输入输出样例
9 4 6 3 6 3 7 2 6 5 2 2 5
2 1
说明/提示
从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力
题意:
鸟儿要从第一棵树飞到最后一棵树,每次只能飞q棵树,飞到不比当前的树矮的树会消耗一点体力,反之则不消耗体力,求每次最少耗费多少体力。
题解:
由题目可以很明显的想到DP来做,并想到dp[i]=min(dp[f]+(tall[f]≤tall[i])) (i-p≤f<i)但这样时间复杂度为O(n^2),所以很明显不可以,但这里我们可以发现,min(dp[f])可以通过单调队列来求出,这样就可以将时间复杂度压缩,因这题会卡STL,所以不能使用deque,具体见下代码。
#define _CRT_SECURE_NO_DepRECATE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <iostream> #include <cmath> #include <iomanip> #include <string> #include <algorithm> #include <bitset> #include <cstdlib> #include <cctype> #include <iterator> #include <vector> #include <cstring> #include <cassert> #include <map> #include <queue> #include <set> #include <stack> #include <stdio.h> #define ll long long #define INF 0x3f3f3f3f #define ld long double const ld pi = acos(-1.0L), eps = 1e-8; ll qx[4] = { 0,0,1,-1 }, qy[4] = { 1,-1,0,0 }, qxx[2] = { 1,-1 }, qyy[2] = { 1,-1 }; using namespace std; int n, tall[1000010], m, k, dp[1000010], num[1000010]; int main() { ios::sync_with_stdio(false); cin.tie(0); int start, end; cin >> n; for (int i = 1; i <= n; i++) { cin >> tall[i];//输入每棵树的高度 } cin >> m; for (int i = 0; i < m; i++) { cin >> k;//输入每次能跳几棵树 memset(dp, 0, sizeof(dp)); start = 1; end = 1; num[1] = 1; for (int f = 2; f <= n; f++) { while (start <= end && f - num[start] > k)//如果最开始的那棵树不能跳到f则start++ { start++; } dp[f] = dp[num[start]] + (tall[num[start]] <= tall[f]);//如果start那棵树的高小于等于f那棵树的高度则还需+1 while (start <= end && (dp[num[end]] > dp[f] || ((dp[num[end]] == dp[f] && tall[f] >= tall[num[end]])))) { end--;//队列为单调递增,所以当end的值应该小于dp[f],当他们的值相同时,取高度更高的那一棵树 } num[++end] = f;//将f放进队尾 } cout << dp[n] << endl; } return 0; }