2022-05-08每日刷题打卡
代码源——每日一题
三段式 - 题目 - Daimayuan Online Judge
有一个长度为n的序列,现在我们想把它切割成三段(每一段都是连续的),使得每一段的元素总和都相同,请问有多少种不同的切割方法
输入描述
第一行给出一个数n,(1≤n≤10^5)
第二行给出序列a1,a2,a3,…,an,(|ai|≤10^5)
输出描述
输出一个数表示有多少种不同的切割方法
样例输入
4
1 2 3 3
样例输出
1
样例解释
可以将它分成第一组1,2,第二组3,第三组3
问题解析
前缀和,我们既然要把数组分成三组,那么实际上我们已经可以知道这三组的和是多少了,毕竟原数组的和是固定的,设为sum,现在我们要把他们分成三个子数组,且这三个子数组和要相等,相当于这三个子数组的和都是sum/3。所以我们可以先判断一下sum能否被3整除,要是不行,那么就肯定不能切割了。
我们可以先算出原数组的前缀和数组,然后根据sum找点分割数组,找到sum/3的点和sum/3*2的点,我们可以把这些点的下标分别存起来,然后在sum/3 *2的点前面找sum/3的点,算组合数。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e4 + 50;
int main()
{
int n;
cin >> n;
if (n < 3)
{
cout << 0 << endl;
return 0;
}
vector<ll>v(n), sum(n);
unordered_map<int, int>mymap;
cin >> v[0];
sum[0] = v[0];
for (int i = 1; i < n; i++)cin >> v[i], sum[i] = sum[i - 1] + v[i];
if (sum[n - 1] % 3 != 0)
{
cout << 0 << endl;
return 0;
}
ll a = sum[n - 1] / 3, b = a * 2;
set<ll>one, two;
int cnt = 0;
bool flag = true;
for (int i = 1; i < n-1; i++)
{
if (sum[i] == a)
{
cnt++;
one.insert(i);
mymap[i] = cnt;
}
if (sum[i] == b)two.insert(i);
}
if (one.empty() || two.empty())
{
cout << 0 << endl;
return 0;
}
ll res = 0;
for (auto i : two)
{
auto it = one.upper_bound(i);
it--;
res += mymap[*it];
}
cout << res << endl;
return 0;
}