文章目录
- Question
- Ideas
- Code
Question
给定一个长度为 n
的数组 a1,a2,…,an
。
现在,要将该数组从中间截断,得到三个非空子数组。
要求,三个子数组内各元素之和都相等。
请问,共有多少种不同的截断方法?
输入格式
第一行包含整数 n
。
第二行包含 n
个整数 a1,a2,…,an
。
输出格式
输出一个整数,表示截断方法数量。
数据范围
前六个测试点满足 1≤n≤10
。
所有测试点满足 1≤n≤105
,−10000≤ai≤10000
。
输入样例1:
4
1 2 3 3
输出样例1:
1
输入样例2:
5
1 2 3 4 5
输出样例2:
0
输入样例3:
2
0 0
输出样例3:
0
Ideas
前缀和+枚举,重点是理解为什么可以优化成枚举一个端点
Code
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
typedef long long LL; // 范围是1e5, 从里面选两个边界点,1e10 > int (范围2e9) 会爆int
int main()
{
int n;
scanf("%d", &n);
// 前缀和
for (int i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
a[i] += a[i - 1];
}
// 要三等分和必须是3的倍数
if (a[n] % 3) puts("0");
else
{
LL cnt = 0, total = 0; // 防止爆int
// 遍历j,满足第一部分为S/3,最后一部分为S/3即满足条件;
for (int j = 2; j < n; j ++) // 集合不能存在空集,所以j的遍历范围为[2,n-1];
{
if (a[j - 1] == a[n] / 3) cnt ++; // 第一部分满足条件
if (a[j] == a[n] / 3 * 2) total += cnt; // 第二部分满足条件
}
printf("%lld", total);
}
return 0;
}