Little Bird
POI2014
题意
1.有一排n棵树,第i棵树的高度是D[i]。
2.有m只小鸟要从第1棵树到第n棵树
3.如果第j只小鸟当前在第i棵树,那么它可以跳到第i+1,i+2,…,i+k[j]棵树。
4.如果小鸟跳到一棵高度大于等于当前高度的树,那么它的劳累值会加一,否则不会。
5.每只鸟最少会有多少疲劳值。
解
1.先写一个无脑dp
定义 dp[i]:到了i位置时最少的疲劳值是多少
dp转移
dp[i]={dp[j]+(H[i]>=H[j])} (i-K<=j<i)
2.尝试优化
探索单调性
考虑两决策,j,k谁更优
①如果 dp[j]<dp[k] 那么j决策更优
因为 dp[j]+1<=dp[k]
②如果 dp[j]=dp[k],H[j]>H[k] 那么j决策更优
因为 对于k决策要费用时,j决策不一定需要费用
因此可以维护一个单调队列,令队首的决策是最优的。
1.每次先把j<i-K的决策弹掉
2.取出队首计算dp[i]
3.弹掉队尾比dp[i]不优的决策
4.把决策i放入队尾
具体代码
#include<bits/stdc++.h>
using namespace std;
const int M=1000005;
int n,m,H[M],K;
int dp[M];
struct node{
int id,dp,H;
}q[M];
void solve() {
int l=1,r=1;
dp[1]=0;
q[r++]=(node){1,0,H[1]};
for(int i=2; i<=n; i++) {
while(l<r&&i-q[l].id>K)l++;
dp[i]=q[l].dp+(H[i]>=q[l].H);
while(l<r){
if(dp[i]<q[r-1].dp||dp[i]==q[r-1].dp&&H[i]>q[r-1].H)r--;
else break;
}
q[r++]=(node){i,dp[i],H[i]};
}
printf("%d\n",dp[n]);
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&H[i]);
}
scanf("%d",&m);
for(int i=1; i<=m; i++) {
scanf("%d",&K);
solve();
}
return 0;
}