专栏文章

题解:P11963 [GESP202503 六级] 环线

P11963题解参与者 3已保存评论 5

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
5 条
当前快照
1 份
快照标识符
@miptwzh1
此快照首次捕获于
2025/12/03 17:53
3 个月前
此快照最后确认于
2025/12/03 17:53
3 个月前
查看原文
begin

前言(渺小)


考试的时候打了一个超级无敌大歪解,个人认为漏洞百出,但是还是成功的骗到了 90%90\% 的分数。(大概是数据的锅。?)
考后看到标签后恍然大悟,造就了这篇题解。
另:不会单调队列的可以去看看 P1886 滑动窗口 /【模板】单调队列

思路

我们简化一下题目:截取一个长度 n\le n 的序列,使它的和最大。
那么众所周知,如果要让和最大,那么减掉的就越少越好。
所以我们可以先求出破环成链后的 aa 数组的前缀和 sumsum 数组,然后对于每一个 1i2n1\le i \le 2n 在确保长度不超过 nn 的情况下,减掉一个最小的前缀和,最后取最大值即可。
针对上述思路,单调队列简直再合适不过了。

Code

CPP
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const ll N=4e5+10;
ll n,a[N],sum[N],q[N],head=1,tail,ans=-1e10;
int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;
    // 破环成链
    for (ll i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
    // 前缀和
    for (ll i=1;i<=n*2;i++) sum[i]=sum[i-1]+a[i];
    // 单调队列
    for (ll i=1;i<=n*2;i++)
    {
    	while (head<=tail && i-q[head]>n) head++; // 确保区间长度合法
    	while (head<=tail && sum[q[tail]]>=sum[i]) tail--; // 构造递增队列的
    	ans=max(ans,sum[i]-sum[q[head]]); // 取最大值
        q[++tail]=i; // 扔进去
    }
    cout<<ans;
    return 0;
}
end

评论

5 条评论,欢迎与作者交流。

正在加载评论...