洛谷 P3572 [POI2014]PTA-Little Bird
Description
有一排n棵树,第i棵树的高度是Di。
有一些ZQX要从第一棵树到第n棵树去找他的妹子玩。
如果ZQX在第i棵树,那么他可以跳到第i+1,i+2,…,i+k棵树。
如果ZQX跳到一棵不矮于当前树的树,那么他的劳累值会+1,否则不会。
为了有体力和妹子玩,ZSH要最小化劳累值。
Input
第一行输入有n棵树;
第二行输入这n棵数的高度;
第三行输入有p个ZQX;
第4~p+1行输入这个ZQX可以跳多远;
Output
- 共p行,每一行输出一个ZQX的劳累值。
Sample Input
9 4 6 3 6 3 7 2 6 5 2 2 5
Sample Output
2
1
题解:
- 单调队列优化dp。
- 朴素的dp方程很容易写出:dp[i] = min{dp[j] + a[j] < a[i] ? 1 : 0} (i - k <= j < i)
- 虽然多了一个比前面高度高就要+1的瓜皮操作。但是并没有发生任何影响,仍然可以用单调队列
- 具体就是在插入新元素对比新元素与队尾元素时,如果最小体力一样,取最大高度。否则仍取最小体力。换句话说,体力是第一关键字,高度是第二关键字。
- 这题卡STL,卡常没卡过去,吸了口氧过去的。
懒得改
#include <iostream>
#include <cstdio>
#include <deque>
#define re register
#define N 1000005
using namespace std;
struct Node {int val, dfn;};
int n, q, k;
int a[N], dp[N];
deque<Node> deq;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return x *= f;
}
void solve()
{
deq.clear();
dp[1] = 0;
deq.push_back((Node){0, 1});
for(re int i = 2; i <= n; i++)
{
while(deq.size() && deq.front().dfn + k < i) deq.pop_front();
dp[i] = deq.front().val;
if(a[deq.front().dfn] <= a[i]) dp[i]++;
while(deq.size())
if(deq.back().val > dp[i])
deq.pop_back();
else if(deq.back().val == dp[i])
{
if(a[deq.back().dfn] <= a[i])
deq.pop_back();
else break;
}
else break;
deq.push_back((Node){dp[i], i});
}
printf("%d\n", dp[n]);
}
int main()
{
cin >> n;
for(re int i = 1; i <= n; i++) a[i] = read();
cin >> q;
for(re int i = 1; i <= q; i++)
{
k = read();
solve();
}
return 0;
}