1. 程式人生 > >POI2014 Little Bird

POI2014 Little Bird

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; }