洛谷 P1725 琪露诺(线段树优化dp)

题目链接

https://www.luogu.com.cn/problem/P1725

思路

我们令 d p i dpi dpi表示琪露诺移动到第 i i i个格子时能够获得的最大冰冻指数。

显然,状态转移方程为: d p i = m a x ( d p i , d p k + a i ) dpi = max(dpi,dpk+ai) dpi=max(dpi,dpk+ai),其中 k + L ≤ i k+L \le i k+L≤i并且 ( k + R ≥ i ) (k+R \ge i) (k+R≥i)。

因为 L L L和 R R R的值很大,所以我们可以使用线段树来进行优化。

使用线段树维护区间 d p i dpi dpi的最大值,每计算出一个新的 d p i dpi dpi,就将其扔到线段树中。我们令编号从 1 1 1开头,则最后的答案为 d p n + 2 dpn+2 dpn+2。

代码

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double

typedef long long i64;
typedef unsigned long long u64;
typedef pair<int, int> pii;

const int N = 2e5 + 5, M = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;

int n, l, r;
int a[N], dp[N];
struct segmenttree
{
    struct node
    {
        int l, r, maxx, tag;
    };

    vector<node>tree;

    segmenttree(): tree(1) {}
    segmenttree(int n): tree(n * 4 + 1) {}

    void pushup(int u)
    {
        auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
        root.maxx = max(left.maxx, right.maxx);
    }

    void pushdown(int u)
    {
        auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
        if (root.tag)
        {
            left.tag = root.tag;
            right.tag = root.tag;
            left.maxx = root.tag;
            right.maxx = root.tag;
            root.tag = 0;
        }
    }

    void build(int u, int l, int r)
    {
        auto &root = tree[u];
        root = {l, r};
        if (l == r)
        {
            root.maxx = -inf;
            return;
        }
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }

    void modify(int u, int l, int r, int val)
    {
        auto &root = tree[u];
        if (root.l >= l && root.r <= r)
        {
            root.maxx = val;
            root.tag = val;
            return;
        }
        pushdown(u);
        int mid = root.l + root.r >> 1;
        if (l <= mid) modify(u << 1, l, r, val);
        if (r > mid) modify(u << 1 | 1, l, r, val);
        pushup(u);
    }

    int query(int u, int l, int r)
    {
        auto &root = tree[u];
        if (root.l >= l && root.r <= r)
        {
            return root.maxx;
        }
        pushdown(u);
        int mid = root.l + root.r >> 1;
        int res = -inf;
        if (l <= mid) res = query(u << 1, l, r);
        if (r > mid) res = max(res, query(u << 1 | 1, l, r));

        return res;
    }
};
void solve()
{
    cin >> n >> l >> r;
    fill(dp, dp + 1 + n + 2, -inf);
    for (int i = 1; i <= n + 1; i++)
    {
        cin >> a[i];
    }
    segmenttree smt(n + 1);
    smt.build(1, 1, n + 1);
    dp[1] = a[1];
    smt.modify(1, 1, 1, dp[1]);
    for (int i = 2; i <= n + 1; i++)
    {
        if (i - l < 1)
        {
            dp[i] = -inf;
            continue;
        }
        dp[i] = max(dp[i], smt.query(1, max(i - r, 1ll), max(i - l, 1ll)) + a[i]);
        smt.modify(1, i, i, dp[i]);
    }
    //n+2表示对岸,包括>n+1的所有格子,所以要特殊处理。
    dp[n + 2] = smt.query(1, max(n + 2 - r, 1ll), max(n + 2 - 1, 1ll));
    cout << dp[n + 2] << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int test = 1;
    // cin >> test;
    for (int i = 1; i <= test; i++)
    {
        solve();
    }
    return 0;
}
相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
m0_547486663 天前
《数据结构教程》全套 PPT课件2026
数据结构
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法