zoukankan      html  css  js  c++  java
  • 暑假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
  • 相关阅读:
    Codeforces 611C. New Year and Domino 动态规划
    POJ2585 Window Pains 拓扑排序
    HDOJ1242 Rescue(营救) 搜索
    codeforces 数字区分 搜索
    ZOJ2412 Farm Irrigation(农田灌溉) 搜索
    hdu 4389 X mod f(x) 数位dp
    hdu 4734 F(x) 数位dp
    Codeforces Beta Round #51 D. Beautiful numbers 数位dp
    hdu 3652 B-number 数位dp
    bzoj 1026: [SCOI2009]windy数 数位dp
  • 原文地址:https://www.cnblogs.com/sto324/p/11222433.html
Copyright © 2011-2022 走看看