我们需要判断一个正整数序列 a 是否是“平衡的”。
平衡的定义:存在一个位置 i(1≤i<n),使得前 i 个数的总和 等于 第 i+1 到第 n 个数的总和。也就是说,在序列的某个位置切一刀,左半部分的和与右半部分的和相等。
输入格式:多组测试数据,每组数据给出长度 n 和序列 a1∼an。
输出格式:对每组数据输出 Yes 或 No。
记整个序列的总和为 S。
如果我们选择一个分界点 i,那么:
由于 L+R=S,要使 L=R,必须有 L=R=2S。
因此问题转化为:是否存在某个位置 i,使得前 i 个数的前缀和恰好等于总和的一半?
需要注意:
No。我们可以采用计算前缀和并实时判断的方法:
Yes 或 No。该方法只需要一次遍历即可完成判断。
样例验证:
1 2 3,总和 S=6,i=2 时前缀和为 3,2×3=6,输出 Yes。2 3 1 4,总和 S=10,i=2 时前缀和为 5,2×5=10,输出 Yes。1 2 3 4 5,总和 S=15 为奇数,不可能找到,输出 No。对于每组测试数据:
整体每组时间复杂度为 O(n)。
共有 t 组数据,总时间复杂度为 O(∑n)。在题目给定的数据范围(t≤100,n≤10000)下可以轻松通过。
cpp1#include<bits/stdc++.h> 2using namespace std; 3 4int a[10010]; // 存储序列,题目 n ≤ 10000 5 6int main() { 7 int t; 8 cin >> t; 9 while (t--) { // 处理每组测试数据 10 int n; 11 cin >> n; 12 int sum = 0; 13 for (int i = 1; i <= n; i++) { 14 cin >> a[i]; 15 sum += a[i]; // 同时计算总和 16 } 17 int tot = 0, fl = 0; 18 // 遍历前 n-1 个元素,计算前缀和 19 for (int i = 1; i < n; i++) { 20 tot += a[i]; // 累加得到前 i 项和 21 if (tot * 2 == sum) { // 判断是否为总和的一半 22 fl = 1; // 找到平衡点 23 break; 24 } 25 } 26 if (fl) cout << "Yes\n"; 27 else cout << "No\n"; 28 } 29 return 0; 30}
代码说明:
sum 记录整个序列的总和。tot 记录当前的前缀和。fl 作为标记,fl == 1 表示已找到平衡点。tot * 2 == sum 来避免浮点数和整除的问题,即使 sum 是奇数也能正确判断(此时等式不可能成立)。break 可以节省时间。这道题考察了对前缀和的简单应用,只要理清“总和的一半”这个条件,代码实现就不难了。