DTOJ#2922. Little Bird —— POI2014
一些牢骚
灾祸从天而降的时候真是躲也躲不掉。被英语老师连续点名听写背诵,五十个人,连续两次。然而上课的时候太困水掉了,于是一整天都在被罚,作业也没写完,真是心态爆炸。
题目描述
In the Byteotian Line Forest there are 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. , then in a single flight leg it can fly to any of the trees no.i+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 least as 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 least tiresome, 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 get from 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 . Help all the birds, little and big!
在森林里有一排树。在第一棵树的顶端,有一只小鸟想飞到最后一棵树的顶端。事实上,这只鸟很小,可能没有力气不停地飞到那里。它一次飞行可以飞到树号i+1,i+2…i+K中的任何一个,然后必须休息。
而且,向上飞比向下飞难得多。如果一次飞行的的终点至少与起点一样高,那么它会很累。否则飞行的航段就不累了。
选择小鸟降落的树,使整个飞行过程最不令人厌烦,也就是说,使它很累的飞行次数最少。现在有一群鸟要飞行,他们的体力分别是Kn,也就是说对于第n只鸟,一次飞行可以降落到i+1,i+2…i+Kn中的任何一个。
输入格式
标准输入的第一行有一个整数N(2<=N<=1000 000):树的数量。第二行输入整数D1,D2…Dn(1<=Di<=10^9),用单个空格分隔:Di是第i棵树的高度。
输入的第三行包含一个整数Q(1<=Q<=25):需要计划飞行的鸟的数量。下面的Q行描述这些鸟:在第i行中,有一个整数Ki(1<=Ki<=N-1)指定第i只鸟的耐力。
输出格式
第n行输出第n只鸟疲劳的飞行次数。
样例输入
9
4 6 3 6 3 7 2 6 5
2
2
5
样例输出
2
1
解法
单调队列dp的模板题。
dist[i]=min(dist[j]+(D[j]≤D[i])),(max(1,i−K)≤j<i) dist[i]表示从第1棵树到第i棵树的步数。
每次更新dist[i]时,只选取dist[j]最小的那个,如果dist相同,显然选取D[j]最大的那个。
可以维护一个单调队列(可以用数组模拟),从队尾到队首按照dist从大到小存树的位置,这样对于第i棵树,只需要用队头更新dist[i]就行了。
如果dist相同,那么高度D应该 从队尾到队首按照高度从小到大存数的位置。
我们知道随着dist增加,步数不减小。所以每次用队首更新完dist[i]后,在i入队之前,应该把队尾dist>dist[i]的全部弹掉,然后把dist=dist[i]且D<=D[i]的弹掉。
最后把i放进队尾。
时间复杂度O(n)
#pragma GCC optimize(3) #include<iostream> #include <stdio.h> using namespace std; int tree[1000010]; int dist[1000010]; int que[1000010]; int N,Q,L,R; inline int read() { char ch; while (!isdigit(ch = getchar())) ; int sum = (int)ch ^ 48; while (isdigit(ch = getchar())) sum = (sum << 1) + (sum << 3) + ((int)ch ^ 48); return sum; } int main(){ N=read(); for(int f=1;f<=N;f++) tree[f]=read(); Q=read(); int K; while(Q-->0){ K=read(); dist[1]=0; L=0; R=0; que[0]=1; for(int f=2;f<=N;f++){ if(que[L]<f-K) ++L; if(tree[que[L]]>tree[f]) dist[f]=dist[que[L]]; else dist[f]=dist[que[L]]+1; while(dist[que[R]]>dist[f]) --R; while(dist[que[R]]==dist[f]&&tree[que[R]]<=tree[f]) --R; que[++R]=f; } cout<<dist[N]<<endl; } } //为了飚速度emmm

浙公网安备 33010602011771号