洛谷 P1725 琪露诺

洛谷 P1725 琪露诺

Description

  • 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。

    某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来。但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸。于是琪露诺决定到河岸去追青蛙。

    小河可以看作一列格子依次编号为0到N,琪露诺只能从编号小的格子移动到编号大的格子。而且琪露诺按照一种特殊的方式进行移动,当她在格子i时,她只移动到区间[i+l,i+r]中的任意一格。你问为什么她这么移动,这还不简单,因为她是笨蛋啊。

    每一个格子都有一个冰冻指数A[i],编号为0的格子冰冻指数为0。当琪露诺停留在那一格时就可以得到那一格的冰冻指数A[i]。琪露诺希望能够在到达对岸时,获取最大的冰冻指数,这样她才能狠狠地教训那只青蛙。

    但是由于她实在是太笨了,所以她决定拜托你帮它决定怎样前进。

    开始时,琪露诺在编号0的格子上,只要她下一步的位置编号大于N就算到达对岸。

Input

  • 第1行:3个正整数N, L, R

    第2行:N+1个整数,第i个数表示编号为i-1的格子的冰冻指数A[i-1]

Output

  • 一个整数,表示最大冰冻指数。保证不超过2^31-1

Sample Input

5 2 3
0 12 3 11 7 -2

Sample Output

11

Data Size

  • 对于60%的数据:N <= 10,000

    对于100%的数据:N <= 200,000

    对于所有数据 -1,000 <= A[i] <= 1,000且1 <= L <= R <= N

题解:

  • 单调队列优化dp
  • dp方程朴素的很容易想到:dp[i] = max{dp[k] + a[i]} (i - r <= k <= i - l)
  • 然后是n^2的算法。200000的N肯定过不去。
  • 问题就出在找max上。
  • 然后可以用数据结构维护或者写一个单调队列。
  • 用数据结构的话我喜欢用线段树,主要是好理解,复杂度是O(nlogn),这里就不展开了。
  • 单调队列可以使复杂度降到O(n),十分优秀。
  • 但单调队列也有几个特点:
    1. 只有与自身无关的dp递推式才能使用单调队列
      • 例:dp[i] = max{dp[k] + M + (sum[i] - sum[k])^2}
      • 这里i位置元素与前面位置元素产生了"纠缠"。故不能用单调队列优化
      • 但可以用斜率优化,这里不展开
    2. 单调队列相对于数据结构,相对难理解一点
  • 单调队列的大概流程/思想:
    • 开一个双端队列,维护一个单调的序列。
    • 每次先检查哪些元素已经不在是dp框选住的位置了,不是的直接弹出
    • 然后可以取出队首,此时队首为维护序列的最优值
    • 然后拿新加入的元素与队尾相比较,不比新元素优的队尾直接弹掉,直到比它优为止
    • 最后推入新元素
  • 这题处理边界比较麻烦,具体看程序。一定注意now的用法!
#include <iostream>
#include <cstdio>
#include <deque>
#define N 200005
using namespace std;

struct Node {int val, dfn;};
int n, l, r, now;
int a[N], dp[N];
deque<Node> deq;

int main()
{
    cin >> n >> l >> r;
    for(int i = 0; i <= n; i++) scanf("%d", &a[i]);
    for(int i = l; i <= n; i++)
    {
        while(deq.size() && deq.front().dfn + r < i) deq.pop_front();
        while(deq.size() && deq.back().val < dp[now]) deq.pop_back();
        deq.push_back((Node){dp[now], now});
        dp[i] = deq.front().val + a[i];
        now++;
    }
    int ans = dp[n];
    for(int i = n - r + 1; i < n; i++) ans = max(ans, dp[i]);
    cout << ans;
    return 0;
}

转载于:https://www.cnblogs.com/BigYellowDog/p/11250155.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值