Bootstrap

牛客小白月赛96 C-最多数组的数量

题目链接:

登录—专业IT笔试面试备考平台_牛客网

解析:

  1. 计算前缀和数组:首先,我们计算一个前缀和数组 s,其中 s[i] 表示从数组 a 的第一个元素到第 i 个元素的和。这样,任意子数组的和可以通过前缀和数组快速计算得出。

  2. 遍历每个可能的左端点:我们从数组的第一个元素开始,遍历每个可能的左端点 i(从 1 到 n-2,因为我们需要至少有一个元素在中间段和右段)。

  3. 二分查找中间点:对于每个左端点 i,我们使用二分查找来找到合适的中间点 l。二分查找的范围是从 i+1 到 n-1

  4. 检查中间段的和:在二分查找的过程中,我们检查当前中间点 mid 是否满足条件:s[mid] - s[i](中间段的和)大于左段的和 s[i] 以及右段的和 s[n] - s[mid]。如果满足,我们就缩小右边界 r;如果不满足,我们就增大左边界 l

  5. 验证找到的中间点:当二分查找结束时,我们得到一个可能的中间点 l。我们需要验证这个点是否真的满足条件。如果满足,那么从 l 到 n-1 的每个元素都可以作为右端点与左端点 i 形成满足条件的子数组。

  6. 更新结果:对于每个满足条件的中间点 l,我们计算从 l 到 n-1 的元素个数(即 n - l),并将其累加到结果 res 中。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;

long long n,ans;
long long a[N],pre[N];

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        pre[i]=pre[i-1]+a[i];
    }
    for(int i=1;i<=n-2;i++){
        int l=i+1,r=n-1;
        while(l<r){
            int mid=(l+r)>>1;
            if(pre[mid]-pre[i]>pre[i]&&pre[mid]-pre[i]>pre[n]-pre[mid]){
                r=mid;
            }
            else
                l=mid+1;
        }
        if(pre[l]-pre[i]>pre[i]&&pre[l]-pre[i]>pre[n]-pre[l]){
            ans+=n-l;
        }
    }
    cout<<ans<<endl;
    return 0;
}
;