CF1285B Just Eat It! - 题解
注:这应该是最快的题解了(总共 \(321\) ms)。
简化题意
判断一个序列是否满足:该序列和严格大于其所有连续子序列和(不包括原序列)
解析
【简化题意】中“严格大于其所有连续子序列和(不包括原序列)”,可以转化成“严格大于非原序列的最大连续子序列和”。所以我们只需要求出“非原序列的最大连续子序列和”并将其与原序列和相比较即可。
求出“非原序列的最大连续子序列和”,我们可以采用 DP 的方法。设 \(p_i\) 表示从 \(a_1\) 到 \(a_i\) 的最大连续子序列和,那么 \(a_n\) 就表示“最大连续字段和”。
对于每个原序列的每个数 \(a_i\),都需要决定是否将其加入之前的连续子序列。
-
对于“加入”的情况,明显 \(p_i=p_{i-1}+a_i\)。
-
对于“不加入”的情况,那么新的 \(p_i=a_i\)。
\(p_i\) 应该取以上两种情况的结果的最大值。即:
\[p_i = \max \begin{cases}
p_{i-1}+a_i \\
a_i
\end{cases}\]
注意要排除“最大连续子序列为原序列”的情况。我们可以用变量 \(l\) 记录最大连续子序列的左端点,当需要把 \(a_n\) 加入序列且 \(l=1\) 时不予更新。
另外,因为 \(p\)、记录总值和记录最大连续子序列的变量均为多个 \(a\) 数组元素累加的结果,所以需要开 long long。
时间复杂度为 \(O(n)\),线性,所有题解中最快。
代码
#include<cstdio>
#define max(x,y) x>y?x:y
#define N 200005
using namespace std;
int t,n;
int a[N];
long long p[N];
int main()
{
scanf("%d",&t);
for(int I=1;I<=t;I++)
{
scanf("%d",&n);
long long tot=0; //tot 记录原序列和
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
tot+=a[i];
}
long long ans=-1000000005; //ans 记录最大连续子序列
int l=1;
for(int i=1;i<=n;i++)
{
if(p[i-1]+a[i]>a[i])
{
if(l==1&&i==n) continue; //排除“最大连续子序列为原序列”的情况
p[i]=p[i-1]+a[i];
}
else p[i]=a[i],l=i; //更改左端点
ans=max(ans,p[i]); //在求 p[i] 时顺便把 ans 也求出来
}
if(tot>ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}
2022-07-10 13:39 撰写于洛谷,2025-08-29 20:25 迁移至博客园。
本文采用 「CC-BY-NC 4.0」 创作共享协议,转载请注明作者及出处,禁止商业使用。
作者:Jerrycyx,原文链接:https://www.cnblogs.com/jerrycyx/p/19065120

浙公网安备 33010602011771号