2021-11-15

dp+滑动窗口的应用

设计了一款游戏,需要算出从起点经过若干次跳跃到终点的得分,输入为一个整数数组nums,和一个整数k,

一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。

你的目标是到达数组尾部(下标为 n - 1 ),你的得分为经过的所有数字之和。

#分析:
由题意可以发现可以用动态规划解决,但是显然在dp时会超时,因为你要每次用一次循环查找[i - k, i - 1] 的最大值。因此此时就需要用滑动窗口维护长度为k - 1的窗口中得分的最大值。

d p [ i ] = d p [ q [ h h ] ] + n u m s [ i ] dp[i] = dp[q[hh]] + nums[i] dp[i]=dp[q[hh]]+nums[i]

Sample Input 1 

1,-1,-2,4,-7,3
2
Sample Output 1

7
解释:你可以选择子序列 [1,-1,4,3],和为 7
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5 + 10;
int k, len;
int nums[N], dp[N], q[N];
string s;
void run()
{
    cin >> s;
    for (int i = 0; i < s.size(); i ++)
    {
        int num;
        if (isdigit(s[i]))
        {
            num = s[i] - '0';
            int j;
            for (j = i + 1; isdigit(s[j]); j ++)
                num = num * 10 + s[j] - '0';
            i = j;
            nums[len ++] = num;
        }
        if (s[i] == '-')
        {
            int j;
            num = 0;
            for (j = i + 1; isdigit(s[j]); j ++)
                num = num * 10 + s[j] - '0';
            i = j;
            nums[len ++] = -num;
        }
    }
    memcpy(dp, nums, sizeof dp);// 初始化dp数组,得分初始是当前的值
    cin >> k;
    dp[0] = nums[0];
    int hh = 0, tt = 0;
    for (int i = 1; i < len; i ++)
    {
        while (hh <= tt && i - k > q[hh]) hh ++;
        dp[i] = dp[q[hh]] + nums[i];
        while (hh <= tt && dp[i] >= dp[q[tt]]) tt --;
        q[++ tt] = i;
    }
    cout << dp[len - 1] << endl;
}
int main() 
{
    ios_base::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    freopen("in.in", "r", stdin);
    run();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值