给定一个长度为 n� 的数组 a1,a2,…,an�1,�2,…,��。
现在,要将该数组从中间截断,得到三个非空子数组。
要求,三个子数组内各元素之和都相等。
请问,共有多少种不同的截断方法?
输入格式
第一行包含整数 n�。
第二行包含 n� 个整数 a1,a2,…,an�1,�2,…,��。
输出格式
输出一个整数,表示截断方法数量。
数据范围
前六个测试点满足 1≤n≤101≤�≤10。
所有测试点满足 1≤n≤1051≤�≤105,−10000≤ai≤10000−10000≤��≤10000。
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 100010;
int n;
int s[N];
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n; i++)
{
scanf("%d",&s[i]);
s[i] += s[i-1]; //前缀和 本题中不需要计算每一项具体的值,只保存前几项的和即可
}
if(s[n] % 3)
{
puts("0");
return 0; //若总和不能被3整除,则必然不能被划分为三段等结果数列
}
ll res = 0,cnt = 0; //cnt 为当最后一段起始项为i时,前面划分每段为sum/3的方案数目
for (int i = 3; i <= n;i++) //i为最后一段的第一位数
{
if(s[i-2] == s[n]/3) cnt++; //i从3起,i-2从1起,此处计算当后一段为3/sum时,0~i-2 = sum/3的划分数,前面每次计算后的结果都保留,故这里只需判定i-2向后移1位时是否满足。满足cnt就+1
if(s[n] -s[i-1] == s[n]/3 )
{
res+= cnt;
}
}
printf("%lld",res);
return 0;
}
收获点:
前缀和表示: s[i] += s[i-1];
在遍历过程累计统计前面[1,i] 符合条件的方案数, 省去二次循环
分为三段相等序列则 总的数组和一定是3 的倍数;