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;
}
posted @ 2023-02-20 11:47  r涤生  阅读(27)  评论(0编辑  收藏  举报