首页 > 其他分享 >洛谷题单指南-动态规划2-P1725 琪露诺

洛谷题单指南-动态规划2-P1725 琪露诺

时间:2024-04-24 18:33:31浏览次数:17  
标签:10 格子 初始化 int 洛谷题 露诺 冰冻 P1725 dp

原题链接:https://www.luogu.com.cn/problem/P1725

题意解读:走过一系列格子之后,冰冻指数之和最大,相当于计算最大子序列的和。

解题思路:

设a[0~n]保存所有冰冻指数

设dp[i]表示以第i号格子为终点所能获得的最大冰冻指数

设j表示i的前一个格子,也就是从j可以移动到i

已知i,则j的范围也很好计算,由于每次在x移动的范围是 x + l ~ x + r之间,所以上一步j的范围是i-r ~ i-l

然后计算dp[j] + a[i]的最大值即可

所以有dp[i] = max(dp[i], dp[j] + a[i]),j取i-r ~ i-l之间,注意j不能小于0

由于冰冻指数有负数,在加法过程中会出现负值,最后要计算最大值,dp的初始化需要小心

看数据范围:-2×10^5≤N≤2×10^5,−10^3≤Ai​≤10^3

所以所有数相加最小是-2×10^8,最大是2×10^8

dp初始化为-1e9就可以,注意千万不要初始化为INT_MIN,这样在做加法时如果加一个负数就会溢出

最后,遍历dp,找到下一步的位置大于n的取最大值。

80分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
int a[N]; //冰冻指数
int dp[N]; //dp[i]表示以第i号格子为终点所能获得的最大冰冻指数
int n, l, r;

int main()
{
    cin >> n >> l >> r;
    for(int i = 0; i <= n; i++) 
    {
        cin >> a[i];
        dp[i] = -1e9; //由于有负数,dp初始化为-1e9,注意不能初始化为INT_MIN,因为再加负数会溢出
    }
    dp[0] = 0; //0号格子可获得0冰冻指数
    for(int i = 1; i <= n; i++) //第一个可到达的格子是l
    {
        for(int j = i - r; j <= i - l; j++) //i的上一个格子范围在i-r~i-l之间
        {
            if(j < 0) continue;
            dp[i] = max(dp[i], dp[j] + a[i]);
        }
    }
    int ans = INT_MIN;
    for(int i = 0; i <= n; i++) 
    {
        if(i + r > n) //下一步的位置编号大于n才算到达对岸
            ans = max(ans, dp[i]);
    }
    cout << ans;

    return 0;
}

以上代码的复杂度为O(n^2),最坏情况下是会超时的,必须做出优化。

这里的优化点在于,对于每一个i,要在j = i-r ~ i-l范围内计算dp[j] + a[i]的最大值,也就是找一个范围是i-r ~ i-l窗口内的最大值。

于是,想到了单调队列,只需要在i>=l之后(l之前0之后的位置都无法走到),开始维护窗口大小是r - l + 1的单调递减队里即可快速获取i-r ~ i-l窗口内的最大值。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
int a[N]; //冰冻指数
int dp[N]; //dp[i]表示以第i号格子为终点所能获得的最大冰冻指数
int q[N]; //单调队列,存dp的下标
int n, l, r;

int main()
{
    cin >> n >> l >> r;
    for(int i = 0; i <= n; i++) 
    {
        cin >> a[i];
        dp[i] = -1e9; //由于有负数,dp初始化为-1e9,注意不能初始化为INT_MIN,因为再加负数会溢出
    }
    dp[0] = 0; //0号格子可获得0冰冻指数
    q[0] = 0; //队列加入一个元素,是dp的下标0
    int head = 0, tail = 0; //队首、队尾
    for(int i = l; i <= n; i++) //i第一个可走的位置是l,右边界正好是0
    {
        dp[i] = dp[q[head]] + a[i]; //直接取窗口内的最大值,即队首元素对应的值
        //下一个要放入队列的下标是右边界加1:i - l + 1
        if(head <= tail && i - l + 1 - q[head] > r - l) head++; //如果队列元素将超过窗口大小,队首出队
        while(head <= tail && dp[q[tail]] <= dp[i - l + 1] ) tail--; //如果队尾元素对应的dp值不比dp[i-r+1]大,则出队,确保单调递减
        q[++tail] = i - l + 1;
    }
    int ans = INT_MIN;
    for(int i = 0; i <= n; i++) 
    {
        if(i + r > n) //下一步的位置编号大于n才算到达对岸
            ans = max(ans, dp[i]);
    }
    cout << ans;

    return 0;
}

 

标签:10,格子,初始化,int,洛谷题,露诺,冰冻,P1725,dp
From: https://www.cnblogs.com/jcwy/p/18156076

相关文章

  • 洛谷题单指南-动态规划2-P1020 [NOIP1999 提高组] 导弹拦截
    原题链接:https://www.luogu.com.cn/problem/P1020题意解读:拦截系统发射导弹的高度依次不增,计算能拦截的最大导弹数以及需要几套拦截系统。解题思路:问题1:最多能拦截多少导弹?由于发射导弹高度不增,所以求一个最长不增子序列即可得到最大拦截数。方法一、O(n^2)做法:动态规划。采......
  • 洛谷题单指南-动态规划1-P1064 [NOIP2006 提高组] 金明的预算方案
    原题链接:https://www.luogu.com.cn/problem/P1064题意解读:用固定钱数购买最大价值的物品。解题思路:背包问题,背包问题里的体积相当于物品价格,价值相当于价格*重要度物品分为主件、附件,主件最多有0/1/2个附件,要选附件必须选相应主件,因此在递推计算dp[j]总价格j能购买的最大价......
  • 洛谷题单指南-动态规划1-P3842 [TJOI2007] 线段
    原题链接:https://www.luogu.com.cn/problem/P3842题意解读:计算1-n的最短路,且每行要覆盖线段。解题思路:既然要每行覆盖线段,那往下一行走时,必然是从线段的端点往下,有可能是从左端点往下,也有可能是从右端点往下。当已知第i行,从1走到第i行的左端点且要覆盖第i行线段的路程可以计算......
  • 洛谷题单指南-动态规划1-P1077 [NOIP2012 普及组] 摆花
    原题链接:https://www.luogu.com.cn/problem/P1077题意解读:n种花选m个的选法,每种花数量为ai。解题思路:设dp[i][j]表示前i种花选j个的选法对于第i种花,可以选0,1,2...min(ai,j)个则有递推式:dp[i][j]=∑dp[i-1][j-k],k取0,1,2...min(ai,j)初始化dp[0][0]=1100分代码:#incl......
  • 洛谷题单指南-动态规划1-P1049 [NOIP2001 普及组] 装箱问题
    原题链接:https://www.luogu.com.cn/problem/P1049题意解读:装尽可能多的物品,使得总体积越大越好,即剩余空间最小,还是一个01背包问题,物品的体积就是其价值。解题思路:01背包模版题,物品体积、价值相同,直接采用一维dp。100分代码:#include<bits/stdc++.h>usingnamespacestd;co......
  • 洛谷题单指南-动态规划1-P1115 最大子段和
    原题链接:https://www.luogu.com.cn/problem/P1115题意解读:计算最大字段和,典型dp问题。解题思路:设a[]表示所有整数,f[i]表示以第i个数结束的最大字段和当f[i-1]>=0时,f[i]=f[i-1]+a[i]否则,f[i]=a[i]因此,递归式为f[i]=max(a[i],f[i-1]+a[i])注意整数可能为负,ans初始......
  • 洛谷题单指南-动态规划1-P1434 [SHOI2002] 滑雪
    原题链接:https://www.luogu.com.cn/problem/P1434题意解读:计算能滑行的最长距离。解题思路:设dp(i,j)表示从i,j可以滑行的最大距离对于4个方向i,j可以到达的点,ni,nj,如果可以滑过去(ni,ni所在点高度更低)则dp(i,j)=max(dp(i,j),1+dp(ni,nj))为了便于搜索4个方向的各条路径,......
  • 洛谷题单指南-动态规划1-P2196 [NOIP1996 提高组] 挖地雷
    原题链接:https://www.luogu.com.cn/problem/P2196题意解读:求一条路径,使得所有点地雷数之和最大。解题思路:1、DFS先建图,再从1~n点分别进行一次DFS,记录过程中地雷总数最大的,并且同时记录遍历的顺序。数据量不大,直接就可以过。100分代码:#include<bits/stdc++.h>usingnamespa......
  • 洛谷题单指南-动态规划1-P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles
    原题链接:https://www.luogu.com.cn/problem/P1216题意解读:计算数字三角形最高点到最后一行路径之和最大值,典型线性DP。解题思路:设a[i][j]表示数字三角形的值,设dp[i][j]表示从最高点到第i行第j列路径之和的最大值,由于每一步可以走到左下方的点也可以到达右下方的点,所以dp[i][......
  • 洛谷题单指南-数学基础问题-P1403 [AHOI2005] 约数研究
    原题链接:https://www.luogu.com.cn/problem/P1403题意解读:计算1~n每个数的约数个数之和。解题思路:1、数学方法1~n的约数范围也在1~n,要计算每个数的约数个数之和可以从约数出发,比如约数是x,那么在1~n中一共有n/x个数包含x这个约数x从1一直枚举到n,就可以得出每个约数是多少个......