P1725 琪露诺
题目描述
在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。
某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来。但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸。于是琪露诺决定到河岸去追青蛙。
小河可以看作一列格子依次编号为 0 到 N,琪露诺只能从编号小的格子移动到编号大的格子。而且琪露诺按照一种特殊的方式进行移动,当她在格子 i 时,她只移动到区间 [i+L,i+R] 中的任意一格。你问为什么她这么移动,这还不简单,因为她是笨蛋啊。
每一个格子都有一个冰冻指数 Ai,编号为 0 的格子冰冻指数为 0。当琪露诺停留在那一格时就可以得到那一格的冰冻指数 Ai。琪露诺希望能够在到达对岸时,获取最大的冰冻指数,这样她才能狠狠地教训那只青蛙。
但是由于她实在是太笨了,所以她决定拜托你帮它决定怎样前进。
开始时,琪露诺在编号 0 的格子上,只要她下一步的位置编号大于 N 就算到达对岸。
输入格式
第一行三个正整数 N,L,R。
第二行共 N+1 个整数,第 i 个数表示编号为 i−1 的格子的冰冻指数 Ai−1。
输出格式
一个整数,表示最大冰冻指数。
输入输出样例
输入
5 2 3
0 12 3 11 7 -2
输出
11
说明/提示
对于 60% 的数据,N≤104。
对于 100% 的数据,N≤2×105,−103≤Ai≤103,1≤L≤R≤N。数据保证最终答案不超过 231−1。
代码
无注释版
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
int n,l,r;
int ans=INT_MIN;
int head=1,tail=1;
int num;
int q[N],b[N],dp[N];
void func(){for(int i=l;i<=n;i++){while(tail>=head&&dp[q[tail]]<=dp[i-l]){tail--;}q[++tail]=i-l;while(tail>=head&&q[head]+r<i){head++;}dp[i]=dp[q[head]]+b[i];}
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>l>>r;for(int i=0;i<=n;i++){cin>>b[i];}memset(dp,-0x3f,sizeof(dp));dp[0]=0;func();for(int i=n-r+1;i<=n;i++){ans=max(ans,dp[i]);} cout<<ans<<"\n";
}
有注释版
#include<bits/stdc++.h>
using namespace std;// 定义一个较大的常量 N 用于表示格子的最大数量
#define int long long // 使用 long long 类型,避免处理大整数时溢出
const int N = 2e5 + 10; // N 最大是 2 * 10^5,因此给定足够大的数组空间// 定义所需要的变量
int n, l, r; // n 是格子的数量,l 和 r 是允许的步长范围
int ans = INT_MIN; // 初始化最终结果为最小值,用于后续求最大值
int head = 1, tail = 1; // 双端队列的头尾指针,用于存储索引
int num; // 临时变量
int q[N], b[N], dp[N]; // q 为队列,b 为格子的冰冻指数,dp 数组用于存储每个格子的最大冰冻值// func 函数用于动态规划的转移
void func(){// 从格子 l 到 n 进行遍历for(int i = l; i <= n; i++){// 从队列的尾部移除所有不满足条件的索引while(tail >= head && dp[q[tail]] <= dp[i - l]){tail--; // 移除尾部元素}// 将当前的格子索引 i-l 添加到队列尾部q[++tail] = i - l;// 如果队列中的元素超出了有效范围,则将队列头部移除while(tail >= head && q[head] + r < i){head++; // 移除头部元素}// 当前格子的 dp 值为队列中最优解的 dp 值 + 当前格子的冰冻指数dp[i] = dp[q[head]] + b[i];}
}signed main(){ios::sync_with_stdio(false); // 快速输入输出cin.tie(0);cout.tie(0);// 输入格子的数量 n,以及步长范围 l 和 rcin >> n >> l >> r;// 输入每个格子的冰冻指数 b[]for(int i = 0; i <= n; i++){cin >> b[i];}// 初始化 dp 数组为负无穷,表示初始时各个格子的冰冻指数不可达memset(dp, -0x3f, sizeof(dp)); // dp 数组初始化为极小值dp[0] = 0; // 起点格子的冰冻指数为 0// 调用 func 函数进行动态规划求解func();// 遍历 n-r+1 到 n 的范围,求解最优解for(int i = n - r + 1; i <= n; i++){ans = max(ans, dp[i]); // 更新最大冰冻指数}// 输出最终答案cout << ans << "\n";
}