1 条题解
-
0
自动搬运
来自洛谷,原作者为

cff_0102
& aqua_qaq | 团子群 185800038 | 如果我死了说明我 AFO 了搬运于
2025-08-24 23:06:27,当前版本为作者最后更新于2024-11-24 14:11:25,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
赛时思路。
不难发现前一个区间的 可以且仅可以做到约束在做后一个区间时踢队尾最多踢到哪里(因为这是上一次踢队头踢到的位置),这样就可以通过上一个 来控制当前踢队尾踢到最优处就停下。而对于第一个区间,程序必须从序列的最左端开始加数。下文中区间的左端点指的是踢队尾应该踢到哪里。
考虑 dp。设 表示最后一个区间右端点选到 ,这个区间的左端点有()或没有()要求必须是 的时候(或者说,是否是第一个区间)的最大答案。
转移时模拟一个单调栈(或者说不踢队头的单调队列),每次从单调栈(队尾)踢出一个数之后就可以用区间左端点取到这里,右端点取到 的答案拿来更新 。最后再用左边第一个大于 的数的答案更新 。记得 只能从 转移,而 则可以从 和 转移。答案是所有 的最大值。代码里有具体的转移式,结合代码更好理解。
注意初始化的问题: 刚开始必须从 转移过来才是有效的,所以没有从 转移而来的 刚开始应该设为无穷小。
因为转移过程是模拟一个单调栈,所以复杂度是 的。
赛时代码加注释:
#include<bits/stdc++.h> #define int long long using namespace std; const int N=5e5+5; int a[N],c[N],s[N]; int dp[N][2]; signed main(){ ios::sync_with_stdio(0);cin.tie(0); int n;cin>>n; for(int i=1;i<=n;i++)cin>>c[i],s[i]=s[i-1]+c[i]; for(int i=1;i<=n;i++)cin>>a[i]; deque<int>q;//exactly a monotonic stack for(int i=1;i<=n;i++){ dp[i][1]=-1e18; while(!q.empty()&&a[q.back()]<a[i]){ dp[i][1]=max(dp[i][1],s[i-1]-s[q.back()-1]+max(dp[q.back()][0],dp[q.back()][1])); //s[i-1]-s[q.back()-1]:从 i-1 踢到 q.back(),要把这里面的所有 c 加起来 //max(dp[q.back()][0],dp[q.back()][1])):左端点设到了 q.back(),这样才会踢到这里停下来;上一个右端点选择 q.back(),因为它不能小于 q.back(),而后面的点全部已经转移或者踢完了 q.pop_back(); } if(!q.empty())dp[i][1]=max(dp[i][1],s[i-1]-s[q.back()]+max(dp[q.back()][0],dp[q.back()][1])); if(!q.empty())dp[i][0]=s[i-1]-s[q.back()]+dp[q.back()][0];//中间踢的加起来,前面的转移过来 else dp[i][0]=s[i-1];//一直踢到开头 dp[i][1]=max(dp[i][1],dp[i][0]);//没有要求必须选最左边 ≠ 我不选最左边 q.emplace_back(i); } int ans=0; for(int i=1;i<=n;i++){ ans=max(ans,dp[i][1]); } cout<<ans; return 0; }
上面是赛时的思路,而实际上本题的 dp 可以优化到不开两倍空间。
把 去掉。 仍然需要初始化为无穷小,这样可以保证 在取最大值的时候只会从前面左端点到达 的状态转移,因为刚开始有且只有 。这样,中间的主体代码就可以优化到更短。
另外,将 改为 并在一开始将 放进 中就可以避免对 是否为空的判断,使代码更加简短。
a[0]=n+1;q.emplace_back(0); int ans=0; for(int i=1;i<=n;i++){ dp[i]=-1e18; while(a[q.back()]<a[i]){ dp[i]=max(dp[i],s[i-1]-s[q.back()-1]+dp[q.back()]); q.pop_back(); } dp[i]=max(dp[i],s[i-1]-s[q.back()]+dp[q.back()]); q.emplace_back(i); ans=max(ans,dp[i]); } cout<<ans;
- 1
信息
- ID
- 10827
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者