• 【洛谷】【动态规划+单调队列】P1725 琪露诺


    【题目描述:】

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

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

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

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

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

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

    【输入格式:】

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

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

    【输出格式:】

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

    [算法分析:]

    一道典型的DP题,已知a[i]为点i的冰冻指数,设f[i]为到达点i时获得的最大冰冻指数

    f[i]的状态是由f[i+l, i+r]转移来的

    f[r]的状态是由f[i-r, i-l]得到的.

    可以求得状态转移方程:

      f[i] = max{f[i - j]} + a[i]

      l <= j <= r <= i

    时间复杂度为O(n2)n ≤ 200000 的范围显然是超时了.

    考虑如何优化:

    显然对于求max{f[i - j]}的过程是可以优化的,

    用优先队列或者线段树?O(n log2 n)确实是一个很优秀的复杂度,但是还有更优的:

    单调队列,时间复杂度为O(n).

    每次把一个f[p]值放入deque中,维护序列的单调性(从大到小),

    但如果某一次队头的元素的坐标已经不足以跳到当前点了,就要把队首pop出去

    所以deque中存放的应是一个结构体或者pair.

    那有没有可能在pop队尾的时候把之后的最优解pop掉呢?

    现在要加入队列的元素坐标一定比队尾元素要大,而其值也比需要被pop掉的队尾元素大,

    所以最优解不管怎么pop都会在队列里。

    [Code:]

     1 //P1725 琪露诺
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<queue>
     6 using namespace std;
     7 
     8 const int MAXN = 200000 + 1;
     9 
    10 int n, l, r;
    11 int a[MAXN];
    12 int f[MAXN];
    13 struct Node {
    14     int v, num;
    15 };
    16 
    17 deque<Node> q;
    18 
    19 inline int read() {
    20     int x=0, f=1; char ch=getchar();
    21     while(ch<'0' || ch>'9') {
    22         if(ch == '-') f = -1;
    23         ch = getchar();
    24     }
    25     while(ch>='0' && ch<='9')
    26         x=(x<<3)+(x<<1)+ch-48, ch=getchar();
    27     return x * f;
    28 }
    29 
    30 int main() {
    31     n = read(), l = read(), r = read();
    32     for(int i=0; i<=n; ++i)
    33         a[i] = read();
    34     int p = 0;
    35     for(int i=l; i<=n; ++i) {
    36 // 求max{f[i-r, i-l]}
    37 //        int maxn = 1 << 31;
    38 //        int s = i-r<0 ? 0 : i-r;
    39 //        for(int j=s; j<=i-l; ++j)
    40 //            maxn = max(maxn, f[j]);
    41         while(!q.empty() && q.back().v < f[p])
    42             q.pop_back();
    43         q.push_back((Node){f[p], p});
    44         while(q.front().num + r < i) q.pop_front();
    45         f[i] = q.front().v + a[i];
    46         ++p;
    47     }
    48     int ans = 1 << 31;
    49     for(int i=n-r+1; i<=n; ++i)
    50         ans = max(ans, f[i]);
    51     printf("%d
    ", ans);
    52 }
  • 相关阅读:
    如何增强Linux和Unix服务器系统安全性
    FTP连接不上的解决方法
    PHP获取当前服务器详细信息
    要想提高电脑开机速度首先需要设置这几个功能
    Centos7下安装iptables防火墙
    centos下LVM配置与管理
    基于LNMP环境的ssh2扩展
    60个开发者不容错过的免费资源库
    MySql命令的基本操作
    存储过程 分页【NOT IN】和【>】效率大PK 千万级别数据测试结果
  • 原文地址:https://www.cnblogs.com/devilk-sjj/p/9072387.html
Copyright © 2020-2023  润新知