【Acwing】【蓝桥杯集训】【前缀和】

前缀和

整体思想:前缀和是一种动态规划的思想。模拟出对应的计算公式

一维前缀和

作用:求任意[l, r]区间的和。时间复杂度O(1)

前缀和公式: s[i] = s[i - 1] + a[i]

部分和公式[l, r]:s[r] - [l - 1]

例题1:截断数组

给定一个长度为 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

思路

首先预处理出前缀和:s[n] / 3表示三段中每一段的和
枚举第三段分割的位置,因为每一段都非空,第一段的和可以看成s[i - 2]
找出所有满足第一段和等于s[n] / 3的cnt数量
再去检验第三段的和s[n] - s[i - 1]是否等于s[n] / 3,满足即可将cnt加到答案中

代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n;
int s[N], cnt[N];

int main()
{
    
    
	cin >> n;
	LL sum = 0;
	// 处理前缀和
	for (int i = 1; i <= n; i ++)
	{
    
    
		cin >> s[i];
		s[i] += s[i - 1];
	}
	if (s[n] % 3)
	{
    
    
		cout << 0 << endl;
		return 0;
	}
	LL res = 0;
	// 枚举第三段的起点
	for (int i = 3, cnt = 0; i <= n; i ++)
	{
    
    
		if (s[i - 2] == s[n] / 3) cnt ++;
		if (s[n] - s[i - 1] == s[n] / 3) res += cnt;
	}
	cout << res << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/laaa123mmm/article/details/129252419
今日推荐