AcWing 3956. 截断数组 [前缀和]
AcWing 3956. 截断数组 [前缀和]
思路
题意是将一串数字从中间切两刀分成三段。每一段的和都相等。
要求这三段每一段的和都相等,那么总和肯定是3的倍数,否则就无解。
求解时,可以枚举第一刀/第二刀 + 前缀和来求解。
题目数组长度是1e5,可能是需要\(O(n)\)或\(O(nlogn)\)来解决,暴力\(O(n^2)\)显然不行。
答案可能爆int:前缀和数组不会爆int,但是答案可能爆int,比如1e5个0答案是1e10会爆int
画图可知,前缀和处理后,s[n]必然是3的倍数,否则无解
求解具体做法是枚举第二刀。
用一个变量维护第一刀切点前缀和是s/3的方案数,当第二刀合法的时候直接加上在这之前的第一刀的方案数即可。这样时间复杂度是O(n)
代码
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int s[N];
LL res;
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++) cin >> s[i];
for(int i = 1;i <= n;i ++) s[i] = s[i-1] + s[i];
if(s[n] % 3) puts("0");
else
{
LL cnt = 0;
for(int i = 3;i <= n;i ++)
{
if(s[i-2] == s[n]/3) cnt ++; // 用cnt变量记录第一个点前缀和是s/3有多少种方案
if(s[n] - s[i-1] == s[n]/3) res += cnt; // 如果第二刀在i这里能切,就加上在这之前第一刀的方案数
}
cout << res;
}
return 0;
}
rds_blogs