[POI2014]Little Bird

题目大意:
  $n(n\le10^6)$个点排成一排,每个点有一个高度$h_i$,现在要从$1$号点跳到$n$号点,从$i$号点出发跳到的点$j$满足$i<j\le i+k$,若$h_j\ge h_i$则增加$1$的代价。给出$q(q\le25)$组询问,对于每次给出的$k$,求从$1$跳到$n$的最小代价。

思路:
  用$f_i$表示从$1$跳到$i$的最小代价,则一个显然的状态转移方程为$f_i=\min\{f_j+[h_i\ge h_j]\}$。然而这样是$O(n^2q)$的,显然会TLE。
  考虑队列优化。若当前要加入队列的点是$i$,队尾元素为$j$。若$f_i<f_j$或$j_i=f_j$且$h_i>=h_j$,用$i$转移一定更优,将$j$出队​。转移时将超过$k$范围内的元素出队,每次用队首元素转移即可。时间复杂度$O(nq)$。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<climits>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int N=1e6+1;
13 int h[N],f[N];
14 std::deque<int> q;
15 int main() {
16     const int n=getint();
17     for(register int i=1;i<=n;i++) h[i]=getint();
18     for(register int m=getint();m;m--) {
19         const int k=getint();
20         q.clear();
21         q.push_back(1);
22         for(register int i=2;i<=n;i++) {
23             while(!q.empty()&&i-q.front()>k) q.pop_front();
24             f[i]=f[q.front()]+(h[i]>=h[q.front()]);
25             while(!q.empty()&&(f[q.back()]>f[i]||(f[q.back()]==f[i]&&h[q.back()]<=h[i]))) q.pop_back();
26             q.push_back(i);
27         }
28         printf("%d\n",f[n]);
29     }
30     return 0;
31 }

 

posted @ 2018-03-25 15:23  skylee03  阅读(108)  评论(0编辑  收藏  举报