题目描述
有Q只猴子要从第一棵树到第n棵树去,第i只猴子一次跳跃的最远距离为Ki。如果它在第x棵树,那它最远可以跳到第x+Ki棵树。如果第j棵树的高度比第i棵树高或相等,那么它从第i棵树直接跳到第j棵树,它的劳累值会增加1。所有猴子一开始在第一棵树,请问每只猴子要跳到第n棵树花费的劳累值最小。
输入
第一行一个整数n,表示有n棵树。(2<=n<=1000000)
接下来第二行给出n个正整数D1,D2,……,Dn(1<=Di<=10^9),其中Di表示第i棵树的高度。
第三行给出了一个整数Q(1<=Q<=25),接下来Q行,给出了每只猴子一次跳跃的最远距离Ki(1<=Ki<=N-1)。
输出
输出Q行,每行一个整数,表示一只猴子的最小的劳累值。
样例输入
9
4 6 3 6 3 7 2 6 5
2
2
5
样例输出
2
1
题解
设f[i][j]:第i只猴子跳到第j棵树的最小劳累值
可以得到
f [ i ][ j ] = min( f[ i ][ ii ] + (d[ j ] >= d[ ii ] ) ) // ii = j - k[ i ]; ii < j;ii ++
再想一想,如果 f[ i ][ jj ]为最小值,那么就算h[i] > h[jj] ,f[ i ][ jj ] + 1 也一定是最小的(可能f[ i ][ jj ] 等于f[i][iii],f[ i ][ jj ] + 1 > f[i][iii],但处理一下就可以了),所以先可以不考虑是否+1,所以可以用一个单调上升序列(s)。因为队头是最小的,所以f[i][j] = f[s[head]] + (h[j] >= h[s[head]]) 。再将f[i][j]进入队列,但这里需要特殊处理一下,如果f[i][j]==f[s[tail]] && h[j] > h[s[tail]]也可将s[tail]踢出序列
参考代码:
for(i = 1;i <= q;i++){
memset(s,0,sizeof s);
head = tail = 1;
f[i][1] = 0;
s[1] = 1;
for(j = 2;j <= n;j++){
while(s[head] < j - k[i] && head < tail)
head++;
f[i][j] = f[i][s[head]];
if (h[j] >= h[s[head]])
f[i][j]++;
while((f[i][j]<f[i][s[tail]]||(f[i][j]==f[i][s[tail]]&&h[j]>h[s[tail]]))&&head<tail)
tail--;
s[++tail] = j;
}
printf("%d\n",f[i][n]);
}