#P3419. 第2题-小周买盒饭
-
1000ms
Tried: 147
Accepted: 30
Difficulty: 5
所属公司 :
百度
时间 :2025年8月19日-研发
-
算法标签>动态规划
第2题-小周买盒饭
解题思路
-
设总和为 S=∑i=1nai。
-
需要判断是否存在“非整段”的连续子段,其和 ≥S。
-
关键结论:所有“非整段”的连续子段的最大子段和,等于
- 在前 n−1 个元素上的最大子段和,和
- 在后 n−1 个元素上的最大子段和 的最大值。即
因为任意非整段子段要么不含第一个元素,要么不含最后一个元素(或两者都不含),因此必出现在上述两段之一中。
-
用 Kadane 算法分别在两段上求最大子段和,若结果 ≥S,输出 Yes,否则 No。
-
时间复杂度:每组 O(n);空间复杂度:O(1)。
复杂度
- 时间:O(n) 每组
- 空间:O(1)
代码实现
Python
import sys
def kadane(a, l, r):
# 计算 a[l..r] 的最大子段和(l、r 为闭区间)
cur = -10**18
best = -10**18
for i in range(l, r + 1):
if cur < 0:
cur = a[i]
else:
cur += a[i]
if cur > best:
best = cur
return best
def main():
data = list(map(int, sys.stdin.read().strip().split()))
t = data[0]
idx = 1
out = []
for _ in range(t):
n = data[idx]; idx += 1
a = data[idx:idx+n]; idx += n
S = sum(a)
# 前 n-1 段与后 n-1 段上的最大子段和
left = kadane(a, 0, n - 2)
right = kadane(a, 1, n - 1)
out.append("Yes" if max(left, right) >= S else "No")
print("\n".join(out))
if __name__ == "__main__":
main()
Java
import java.io.*;
import java.util.*;
public class Main {
static long kadane(int[] a, int l, int r) {
// 计算 a[l..r] 的最大子段和
long cur = Long.MIN_VALUE / 4;
long best = Long.MIN_VALUE / 4;
for (int i = l; i <= r; i++) {
if (cur < 0) cur = a[i];
else cur += a[i];
if (cur > best) best = cur;
}
return best;
}
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
StringBuilder sb = new StringBuilder();
while (T-- > 0) {
int n = sc.nextInt();
int[] a = new int[n];
long S = 0;
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
S += a[i];
}
long left = kadane(a, 0, n - 2);
long right = kadane(a, 1, n - 1);
sb.append(Math.max(left, right) >= S ? "Yes" : "No").append('\n');
}
System.out.print(sb.toString());
}
}
C++
#include <bits/stdc++.h>
using namespace std;
long long kadane(const vector<long long>& a, int l, int r) {
// 计算 a[l..r] 的最大子段和
long long cur = LLONG_MIN / 4, best = LLONG_MIN / 4;
for (int i = l; i <= r; ++i) {
if (cur < 0) cur = a[i];
else cur += a[i];
best = max(best, cur);
}
return best;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
if (!(cin >> T)) return 0;
while (T--) {
int n; cin >> n;
vector<long long> a(n);
long long S = 0;
for (int i = 0; i < n; ++i) { cin >> a[i]; S += a[i]; }
long long left = kadane(a, 0, n - 2);
long long right = kadane(a, 1, n - 1);
cout << (max(left, right) >= S ? "Yes" : "No") << '\n';
}
return 0;
}
题目内容
某片场需要给参演人员采购盒饭,负责后勤的小周来到食堂,食堂里一共有 n 种不同的盒饭,种类标记为 1,2,3,...,n ,每种盒饭都有一个美味度 ai 。ai 越大,表示盒饭越好吃,由于有些盒饭味道可能很奇怪,于是 ai 有可能小于等于 0 。
小周不了解演员们的口味偏好,于是每种盒饭都买了一份。回片场的路上小周在想:能不能找到这样一对 l,r 满足 1≤l≤r≤n ,且不满足 [l,r]=[1,n] (即全选),使得将 [l,r] 这个种类内的盒饭各要一份,其美味度之和大于等于每一种会饭都买一份的美味度之和?
输入描述
第一行一个正整数 T ,表示有 T 组数据。
对于每一组数据,第一行一个正整数 n ; 第二行 n 个数 a1,a2,...,an 。
3≤n≤5∗104,−100≤ai≤100,1≤T≤5
输出描述
对于每一组数型,如果找得到这样的 l,r ,输出 Yes ; 否则,输出 No 。
样例1
输入
2
4
1 2 3 4
3
-5 5 -5
输出
No
Yes
说明
第一组数据,无论 l,r 如何选择都比全选的美味度之和要小;
第二组数据,可以选择 [l,r]=[1,1] ,美味度之和为 −5 ,等于全部选择的美味度之和。
当然也可以选择 [l,r]=[1,2] ,美味度之和为 0 ,大于全部选择的美味度之和。