• [单调队列优化DP]JZOJ 3128 跳格子


    Description

    奶牛们正在回味童年,玩一个类似跳格子的游戏,在这个游戏里,奶牛们在草地上画了一行N个格子,(3 <=N <= 250,000),编号为1..N。


        就像任何一个好游戏一样,这样的跳格子游戏也有奖励!第i个格子标有一个数字V_i(-2,000,000,000 <=V_i <= 2,000,000,000)表示这个格子的钱。奶牛们想看看最后谁能得到最多的钱。


        规则很简单:


        * 每个奶牛从0号格子出发。(0号格子在1号之前,那里没钱)


        * 她向N号格子进行一系列的跳跃(也可以不跳),每次她跳到的格子最多可以和前一个落脚的格子差K格(1 <= K <= N)(比方说,当前在1号格,K=2, 可以跳到2号和3号格子)


        * 在任何时候,她都可以选择回头往0号格子跳,直到跳到0号格子。


    另外,除了以上规则之外,回头跳的时候还有两条规则:


        * 不可以跳到之前停留的格子。


        * 除了0号格子之外,她在回来的时候,停留的格子必须是恰巧过去的时候停留的某个格子的前一格(当然,也可以跳过某些过去时候停留的格子)。简单点说,如果i号格子是回来停留的格子,i+1号就必须是过去停留的格子,但如果i+1号格子是过去停留的格子,i号格子不一定要是回来停留的格子。


        她得到的钱就是所有停留过的格子中的数字的和,请你求出最多奶牛可以得到的钱数。


     

    Input

    * 第1行 1: 两个用空格隔开的整数: N 和 K

    * 第2到N+1行: 第i+1行有一个整数: V_i

    Output

    * 第一行: 一个单个的整数表示最大的钱数是多少。

     

    Sample Input

    5 2
    0
    1
    2
    -3
    4
    

    Sample Output

    4
     

    Data Constraint

     
     

    Hint

    【样例解释】


    在样例中,K=2,一行5个格子,钱数分别为0、1、2、-3、4


        一个合法的序列Bessie可以选择的是0[0], 1[0], 3[2], 2[1], 0[0]。(括号里的数表示钱数)这样,可以得到的钱数为0+0+2+1+0 = 3。


        如果Bessie选择一个序列开头为0, 1, 2, 3, ...,那么她就没办法跳回去了,因为她没办法再跳到一个之前没跳过的格子。


        序列0[0], 2[1], 4[-3], 5[4], 3[2], 1[0], 0[0]是最大化钱数的序列之一,最后的钱数为(0+1-3+4+2+0 = 4)。还有一种可能的最大化钱数的序列是: 0[0] 2[1] 4[-3] 5[4] 3[2] 1[0] 0[0]。

    分析

    我们可以贪心的思考一下,先考虑只跳正数钱的格子,那我们设s[i]为1..i中所有正数的和

    f[i]为跳到i且i-1作为跳回来的格子的最大钱数,那么方程还算挺明显的:f[i]=max{f[j]+s[i-2]-s[j]}+v[i]+v[i-1]

    然后最后答案是max{f[i]+s[i+k-1]-s[i]}

    然后f[j]-s[j]这一段是可以用单调队列优化的 就很简单啦

    #include <iostream> 
    #include <cstdio>
    #include <queue>
    using namespace std;
    typedef long long ll;
    const int N=2.5e5+10;
    int pos[N];
    deque<ll> q;
    int n,k,l,r;
    ll v[N],s[N],ans,f[N];
    
    int main() {
        scanf("%d%d",&n,&k);
        for (int i=1;i<=n;i++) scanf("%lld",&v[i]),s[i]=s[i-1]+(v[i]<0ll?0ll:v[i]);
        l=1;r=0;
        for (int i=2,j=0;i<=n;i++,j++) {
            ll now=f[j]-s[j];
            while (!q.empty()&&q.back()<=now) q.pop_back(),r--;
            q.push_back(now);pos[++r]=j;
            while (!q.empty()&&pos[l]<i-k) l++,q.pop_front();
            f[i]=q.front()+s[i-2]+v[i-1]+v[i];
        }
        ans=f[1]+s[min(1+k,n)];
        for (int i=2;i<=n;i++) {
            ans=max(ans,f[i]+s[min(i+k-1,n)]-s[i]);
        }
        printf("%lld",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    html-标题标签、水平线标签和特殊字符
    htm-文字标签和注释标签
    html-html简介
    scss-函数
    scss-!optional
    scss-@extend
    解决SecureCRT下spark-shell中scala无法删除问题
    Python list降序排序
    Python 字典的一键多值,即一个键对应多个值
    python 数组中如何根据值,获取索引,如何根据索引删除值 , 以及如何根据值删除值
  • 原文地址:https://www.cnblogs.com/mastervan/p/10777581.html
Copyright © 2020-2023  润新知