数串问题--逆序对求解

题目描述

Description
给定一个数串,数串的长度为 n ,现在将一个子串的每个数字之和定义为该子串的数串和,请你求出数串中有多少个子串的数串和为正数。

Input
第一行一个数 n ,表示数串的长度。第二行一共 n 个数,表示数串中的每个数输出就一个数,表示数串中有多少个子串的数串和为正数。

Output
一个正数即答案。

Sample Input 1
4
3 8 -9 2
Sample Output 1
3

Hint
对于100%的数据: n ≤ 100000,所有数之和在int范围之内
Time Limit
1000MS
Memory Limit
256MB

题意分析

首先要明确子串一定是连续的、紧挨着的序列不可以是单个元素!
这道题要求出子串和大于0的个数。

解题思路

首先介绍前缀和的概念,前缀和就是求和1~1 、1 ~ 2、1 ~3、…1 ~ n的和,把他们放入一个数组sum,sum[i]表示1 ~ i的和! 同理后缀和就是求n ~n、n ~n-1…n ~1的和!

这道题和前缀和的关系

首先我们求出前缀和,然后用sum[j]-sum[j] (i<j)
如果sum[j]-sum[i]>0证明 i -1~j 序列和大于0,则子串i -1~j的和大于0
通过上述讲解,我们找出所有满足sum[j]-sum[i]>0的序列就可以得出答案

如何找呢?

我们学习过逆序对问题,这个问题使用归并排序找出所有ai>aj,并且i<j的个数!
但是我们上述分析是sum[j]>sum[i],j>i这是顺序对

怎么办呢?

我们可以求出后缀和,只要后缀和满足sum[i]-sum[j]>0即sum[i]>sum[j]且i<j找出这样的逆序对,就可以得出正确答案!

不懂逆序对,看这个超链接!
逆序对问题–归并排序求解

完整代码

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+10;
int n,ans;
int t[maxn],arr[maxn],sum[maxn];

//归并排序
void merge_sort(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)/2;
    merge_sort(l,mid);
    merge_sort(mid+1,r);

    for(int i=l; i<=r; i++)
    {
        t[i]=sum[i];
    }
    int i=l,j=mid+1;
    for(int cur=l; cur<=r; cur++)
    {
        if(i>mid) sum[cur]=t[j++];
        else if(j>r) sum[cur]=t[i++];
        else if(t[j]>=t[i]) sum[cur]=t[i++];
        else
        {
            ans+=mid-i+1;//统计答案
            sum[cur]=t[j++];
        }
    }
    return;
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&arr[i]);
    }
    //求后缀和
    for(int i=n; i>=1; i--)
    {
        sum[i]=sum[i+1]+arr[i];
    }
    merge_sort(1,n+1);
    printf("%lld",ans);

    return 0;
}

小细节

大家有没有注意到,merge_sort(1,n+1)传入的是n+1而不是n!

明明有n对逆序对啊,为什么呢?

因为,如果序列i ~末尾这个序列也满足和大于0,必须要用这种后缀和表示
sum[i]-sum[末尾+1],注意是末尾+1,这样才能求得 i ~末尾 的序列和!所以要传入第n+1为0的后缀和!

讲解完毕!
如果对你有帮助多多点赞支持!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值