码迷,mamicode.com
首页 > 其他好文 > 详细

暑假D9 T2 extra(单调栈优化DP)

时间:2019-07-21 20:06:55      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:opened   nice   答案   extra   暑假   优化   c++   不能   for   

题意

一条路被划分成了n段,每一段有一个高度,一个人有步幅k,代表他最多可以从第x段一步到第x+k段,当h[x]>h[x+k]时,不消耗体力,否则消耗一点体力,求最后到第n段路时最少消耗的体力,最初在第一段路。

对于 30%的数据,保证 T = 1;
对于另 20% 的数据,保证 N <= 500;
对于 100% 的数据,保证 n< = 1e6, T <= 10,ai在 int 内,0 < K <n。

题解

很容易想到转移方程 f[i]= h[i]<h[j] ? f[j] : f[j]+1 (i-k≤j<i)

怎么优化呢,对于高度不同的路,方程都不一样,该怎么去想。

如果方程一样的话,就是在一个长度为k的区间内找f最小的,那不就是单调栈吗?

但转移方程不同,考虑单调栈对于栈首的弹出只与他是否还属于这个区间有关,只要他还能管这个区间,他就是最优的,所以它与去掉不优解无关。我们去掉不优解是在队尾进行的,且每次比较队尾与当前要插入元素的某个值。

那么考虑什么时候队尾的值一定不比当前元素的值优:当两者f值相同时,如果队尾更矮肯定不优,因为在值相同的情况下,他更可能带来1的代价;

那么队尾元素的f比当前元素的f大呢,队尾也是不优的,或者说可以被代替,因为即使当前元素更矮,它带来了1的代价,得到的答案也是≤队尾得到的答案;

队尾元素的f更小就不能弹掉,和上面相同,即使当前元素更高,队尾元素得到的答案也≤当前元素得到答案。

技术图片
#include<bits/stdc++.h>
using namespace std;

const int maxn=1000005;
int n,m,a[maxn];
int q[maxn],h,t;
int f[maxn];

void nice(){
    int k;scanf("%d",&k);
    h=1;t=0;
    q[++t]=1;
    f[1]=0;
    for(int i=2;i<=n;i++){
        while(h<=t&&i-q[h]>k) h++;
        f[i]= a[i]>=a[q[h]] ? f[q[h]]+1 : f[q[h]];
        while(h<=t&&((a[i]>a[q[t]]&&f[i]==f[q[t]])||(f[i]<f[q[t]]))) t--;
        q[++t]=i;
    }
    printf("%d\n",f[n]);
}

int main(){
    freopen("extra.in","r",stdin);
    freopen("extra.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);
    while(m--) nice();
}
/*9
4 6 3 6 3 7 2 6 5
2
2
5*/
View Code

 

暑假D9 T2 extra(单调栈优化DP)

标签:opened   nice   答案   extra   暑假   优化   c++   不能   for   

原文地址:https://www.cnblogs.com/sto324/p/11222433.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!