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


    题意

    一条路被划分成了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
    ",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
  • 相关阅读:
    php分页类 (来源网络)
    symfony2 symofny3中得到get post session cookies的方法
    symfony route参数
    Symfony2同步数据库的数据表
    mysql中SQL执行过程详解与用于预处理语句的SQL语法
    使用MySQL命令行新建用户并授予权限的方法
    抽象类和接口的区别
    Yaf 使用遇到的坑
    Mysql 常用引擎的特点及选择使用策略
    定时任务 Crontab命令 详解
  • 原文地址:https://www.cnblogs.com/sto324/p/11222433.html
Copyright © 2020-2023  润新知