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

题目链接

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

思路

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

显然,状态转移方程为: d p [ i ] = m a x ( d p [ i ] , d p [ k ] + a [ i ] ) dp[i] = max(dp[i],dp[k]+a[i]) dp[i]=max(dp[i],dp[k]+a[i]),其中 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 ] dp[i] dp[i]的最大值,每计算出一个新的 d p [ i ] dp[i] dp[i],就将其扔到线段树中。我们令编号从 1 1 1开头,则最后的答案为 d p [ n + 2 ] dp[n+2] dp[n+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;
}
相关推荐
DowneyJoy6 分钟前
【Unity3D补充知识点】常用数据结构分析-数组(Array)
数据结构·unity·c#
wanderist.12 分钟前
从Nim游戏到SG函数
c++·算法·蓝桥杯
数据皮皮侠29 分钟前
2285 上市公司组织衰退程度【Dec】2010-2024
大数据·人工智能·算法·制造
daxi15031 分钟前
C语言从入门到进阶——第17讲:字符串函数
c语言·开发语言·算法·蓝桥杯
wljy135 分钟前
第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(个人见解,已完结)
c语言·c++·算法·蓝桥杯
CoderCodingNo37 分钟前
【GESP】C++八级考试大纲知识点梳理 (7) 算法的时间和空间效率分析
开发语言·c++·算法
程序员zgh37 分钟前
C++ 环形队列 从原理到实例演示
c语言·开发语言·数据结构·c++·学习
青瓷程序设计42 分钟前
基于YOLO的安全帽佩戴检测系统~Python+模型训练+2026原创+YOLO算法
python·算法·yolo
Trouvaille ~42 分钟前
【优选算法篇】拓扑排序——逻辑先后与任务依赖的终极拆解
数据结构·c++·算法·leetcode·青少年编程·蓝桥杯·拓扑学
T1an-11 小时前
博乐科技笔试题
科技·算法