记录133

#include<bits/stdc++.h> 
using namespace std; // 使用标准命名空间std
const int N=1e5+5; // 定义常量N,表示数组长度的最大范围

int n; // 定义全局变量n,表示数组的长度
int a[N],b[N]; // 定义数组a和b,分别存储题目给定的两个数组
long long f[N],ans; // 定义f数组记录到达某位置的最大分数,ans记录全局最大和

int main(){ // 正向递推(刷表法)
    ios::sync_with_stdio(false); // 关闭标准流同步,提升输入输出效率
    cin.tie(0); // 解除cin与cout的绑定,加快读取速度
    
    cin>>n; // 读入数组长度n
    for(int i=1;i<=n;i++){ // 循环读入数组a
        cin>>a[i]; // 读入a[i]
    }
    for(int i=1;i<=n;i++){ // 循环读入数组b
        cin>>b[i]; // 读入b[i]
    }
    
    // 正向递推(刷表法):利用当前下标i的状态,去更新后续位置的状态
    for(int i=1;i<=n;i++){
        // 尝试选择当前下标i:更新全局答案ans
        ans=max(ans,f[i]+a[i]); 
        
        // 如果选择当前下标i,可以跳跃到 i+b[i] 的位置,更新该位置的最大分数
        if(i+b[i]<=n){
            f[i+b[i]]=max(f[i+b[i]],f[i]+a[i]);
        }
        
        // 不选择当前下标i:将当前的最大分数直接传递给下一个位置 i+1
        f[i+1]=max(f[i+1],f[i]);
    }
    
    cout<<ans<<"\n"; // 输出在满足下标条件的前提下,a数组对应下标的整数之和的最大值
    return 0; // 程序正常结束
}

题目传送门https://www.luogu.com.cn/problem/P15800


前言

我是一名专注信奥赛(CSP-J/S、NOIP)的教练。

  • 如果你觉得这篇题解对你有帮助,欢迎点击关注我的CSDN账号,我会持续更新高质量算法解析。
  • 我深知算法思维的构建远比单纯通过题目更重要,本系列题解不局限于AC代码的堆砌,而是致力于拆解题目背后的逻辑链条与核心知识点
  • 备赛路上若遇瓶颈,欢迎随时评论或私信,我将甄选典型疑难问题,通过视频讲解或撰写专项文章的形式,为你提供深度答疑。

核心解题思路

这道题是一道非常经典的线性动态规划(DP)问题,其核心难点在于理解下标之间的跳跃约束。

  1. 状态定义
    我们定义 f[i] 表示:当我们处理到第 i 个位置时,能够获得的最大分数(注意:f[i] 代表的是从前面某个位置转移过来,准备在 i 或之后的位置进行决策时的累积得分,它本身不包含 a[i])。

  2. 约束条件的转化
    题目要求如果选择了下标 p_i,那么下一个下标 p_{i+1} 必须满足 p_{i+1} >= p_i + b[p_i]。这意味着,如果我们当前站在位置 i 并决定选择它,那么我们下一次能够进行决策的最早位置就是 i + b[i]

  3. 状态转移(刷表法)
    对于每一个位置 i,我们有两种选择:

    • 选择位置 i:我们将 a[i] 加入总分,并将这个新的总分传递给下一个合法的位置 i + b[i]。即 f[i + b[i]] = max(f[i + b[i]], f[i] + a[i])。同时,因为选择了 i,我们可以用 f[i] + a[i] 去更新全局的最大答案 ans
    • 不选择位置 i:如果我们放弃位置 i,那么当前累积的分数 f[i] 可以原封不动地传递给下一个相邻位置 i + 1。即 f[i + 1] = max(f[i + 1], f[i])
  4. 最终答案
    在遍历过程中,我们随时记录 f[i] + a[i] 的最大值,最终输出这个全局最大值即可。


 代码分块详细解释

1. 头文件、常量与全局变量定义

#include<bits/stdc++.h> 
using namespace std; 
const int N=1e5+5; // 定义常量 N,表示数组长度的最大范围

int n; // 定义全局变量 n,表示数组的长度
int a[N], b[N]; // 定义数组 a 和 b,分别存储题目给定的两个数组
long long f[N], ans; // 定义 f 数组记录到达某位置的最大分数,ans 记录全局最大和
  • 详细分析:这部分搭建了算法的基础。由于数组长度 n 最大为 10^5,且 a_i 最大可达 10^9,累加后的总分数可能会超过 int 的范围,因此 f 数组和答案 ans 必须使用 long long 类型来防止数据溢出。

2. 输入处理

int main(){ 
    ios::sync_with_stdio(false); // 关闭标准流同步,提升输入输出效率
    cin.tie(0); // 解除 cin 与 cout 的绑定,加快读取速度
    
    cin>>n; // 读入数组长度 n
    for(int i=1;i<=n;i++){ // 循环读入数组 a
        cin>>a[i]; // 读入 a[i]
    }
    for(int i=1;i<=n;i++){ // 循环读入数组 b
        cin>>b[i]; // 读入 b[i]
    }
  • 详细分析:在读取数据之前,使用了标准的 IO 加速语句。在 n 达到 10^5 级别时,这能有效避免因为输入输出过慢而导致的超时。随后依次读入两个数组的数据,为接下来的动态规划做准备。

3. 核心逻辑:正向递推(刷表法)

    // 正向递推(刷表法):利用当前下标 i 的状态,去更新后续位置的状态
    for(int i=1;i<=n;i++){
        // 尝试选择当前下标 i:更新全局答案 ans
        ans = max(ans, f[i] + a[i]); 
        
        // 如果选择当前下标 i,可以跳跃到 i + b[i] 的位置,更新该位置的最大分数
        if(i + b[i] <= n){
            f[i + b[i]] = max(f[i + b[i]], f[i] + a[i]);
        }
        
        // 不选择当前下标 i:将当前的最大分数直接传递给下一个位置 i+1
        f[i + 1] = max(f[i + 1], f[i]);
    }
  • 详细分析:这是整个算法的灵魂,采用了“刷表法”(即由当前状态去更新未来状态)。
    • 更新全局最优解f[i] 表示到达位置 i 之前(不包含 i)的最大累积分数。如果我们在位置 i 停下并选择它,那么当前的总分就是 f[i] + a[i]。我们随时用这个值去挑战全局最大值 ans
    • 跳跃转移(选择 i):如果决定选择 a[i],根据题目约束 p_{i+1} >= p_i + b[p_i],下一个能够做决策的位置至少是 i + b[i]。我们将当前获得的总分 f[i] + a[i] 传递给 f[i + b[i]],并取最大值。
    • 相邻转移(不选 i):如果我们决定放弃 a[i],那么位置 i 就没有产生任何价值,也没有触发跳跃限制。因此,到达位置 i 的累积分数 f[i] 可以直接顺延到下一个位置 i + 1。这保证了我们可以连续跳过某些位置。

4. 输出结果

    cout << ans << "\n"; // 输出在满足下标条件的前提下,a 数组对应下标的整数之和的最大值
    return 0; // 程序正常结束
}
  • 详细分析:在遍历完所有位置后,ans 中存储的就是所有合法下标组合中,a 数组对应下标整数之和的最大值,直接输出即可。

核心逻辑总结表

代码模块 核心变量/操作 精炼作用 解决的痛点
数据类型 long long f[N], ans 使用 64 位长整型 防止 a_i (最大 109) 累加时超出 int 范围导致数据溢出
IO 优化 ios::sync_with_stdio(false) 提升输入输出效率 解决 10^5 级别数据量下 cin/cout 可能导致的超时问题
状态定义 f[i] 记录到达位置 i 时的最大累积分数 将复杂的下标跳跃约束,转化为线性的状态传递问题
跳跃转移 f[i+b[i]] = max(...) 处理“选择当前下标”的情况 完美契合题目中 p_{i+1} >= p_i + b[p_i] 的约束条件
顺延转移 f[i+1] = max(f[i+1], f[i]) 处理“不选当前下标”的情况 允许程序跳过某些下标,保证决策的灵活性
全局打擂 ans = max(ans, f[i]+a[i]) 实时更新最终答案 确保能够捕获到遍历过程中出现的任何合法的最大分数
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐