专栏文章
题解:P10579 [蓝桥杯 2024 国 A] 最长子段
P10579题解参与者 6已保存评论 9
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 9 条
- 当前快照
- 1 份
- 快照标识符
- @miqkqekg
- 此快照首次捕获于
- 2025/12/04 06:23 3 个月前
- 此快照最后确认于
- 2025/12/04 06:23 3 个月前
begin
Part 0 前置芝士
前缀和,二分。
Part 1 题目分析
题意已经清晰了,无需多言。
这题一个最明显也是最好想的思路就是暴力,但是显然时间复杂的是 的。而 的最大值可以达到 ,所以这样必 TLE,但是你拿到 60 pts 后可以去借鉴别人代码了。
我们思考一下比 耗时更少的复杂度,最终我们锁定了 、 和 三种时间复杂度。
经过简单的思考深思熟虑过后,我们发现,这题用 来求解可能不太现实(或者可能是我太弱了 /bei),而 的耗时也有些极限,所以我们考虑 。
再思考一下,由于 出现的场合比较有限,常见的就两种,一种是排序,另一种就是二分。
很显然,这题跟排序连一分钱关系都没有,所以我们最终锁定二分。
Part 2 解题思路
二分最重要的就是单调性,没有一个单调性的数组这一切就全都是空谈。所以我们现在的问题就是如何构建一个与题目有关的且具有单调性的数组呢?
我们将目光放在题目所给的那一大段条件上(以下我们记 为 的和):
我们考虑用一个数组 存储左端点(),然后为了保证其单调性和正确性,我们得出数组 的递推式为:
为什么要取 呢?
当 时,我们来讨论一下:
当 时,我们来讨论一下:
- 如果 ,它对答案的贡献就是:
- 如果 ,它对答案的贡献是: 显然前者更优,足足比后者大了 呢!
这也同时保证了 数组的单调不增的性质,为接下来的二分做好了准备。
Part 3 Tips
到了这里,这道题你就已经完成 90% 了。但是正所谓行百里者半九十,所以最后的写代码环节也是至关重要的。如果你搞不定细节,那一样完蛋。
大前提:
-
我用的二分方法是
while (l+1<r),如果你的方法和我不同的话可以参考一下思路。 -
以下我们设 。
Part 3.1
首先需要注意的就是二分时 的初始值(这个跟上面的 没关系!)究竟是 还是 ?
我们来举个栗子:若 ,当 时,;时,。
显然 是正确结果。所以 的初始值为 。
Part 3.2
然后就是每个二分的易错点:内部判断条件是
if (f[mid]<=x) r=mid 还是 if (f[mid]<x) r=mid?要找到这个问题的答案,我们首先要知道我们的目标是找到 数组的第一个 使 ,所以在 的时候我们要继续找更小的 ,也就是找更大的 ,也就是右移左端点,也就是 。
所以后者是正确的。
Part 4 Code
CPP#include <bits/stdc++.h>
using namespace std;
using ll=long long;
ll n,a,b,c,sum[300010],now,f[300010],x,l,r,mid,pos,ans;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); // 输入输出加速
cin>>n>>a>>b>>c;
for (ll i=1;i<=n;i++)
{
cin>>now; // 省点空间
sum[i]=sum[i-1]+now; // 前缀和
}
f[0]=1e18; // 是极大值就行,防止第一次 min 出祸
for (ll i=1;i<=n;i++)
{
f[i]=min(f[i-1],sum[i-1]-a*c*i); // 求 f 数组
x=sum[i]-a*b*i; // x
l=0,r=i+1;
while (l+1<r)
{
mid=(l+r)>>1;
if (f[mid]<x)
{
r=mid;
}
else
{
l=mid;
}
}
if (i>=r)
{
ans=max(ans,i-r+1); // 维护最大答案
}
}
cout<<ans;
return 0; // 完结撒花~
}
end
相关推荐
评论
共 9 条评论,欢迎与作者交流。
正在加载评论...