https://www.luogu.org/problemnew/show/P2309
思路
求一下前缀和,如有Si-Sj>0,即Si>Sj
则j+1到i的子段和>0
ans = 正序对个数+0到i的子段和中>0的个数即前缀和>0的个数
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
ll n,ans;
ll num[5000010],sum[5000010],tmp[5000010];
void merge_s(ll l,ll r)
{
if(l==r)
return;
ll mid=(l+r)>>1;
merge_s(l,mid);
merge_s(mid+1,r);
ll i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(num[i]>num[j])
{
tmp[k++]=num[j++];
ans+=mid-i+1;
}
else
tmp[k++]=num[i++];
}
while(i<=mid)
tmp[k++]=num[i++];
while(j<=r)
tmp[k++]=num[j++];
for(ll i=l;i<=r;i++)
num[i]=tmp[i];
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
sum[i]=sum[i-1]+num[i];
}
for(ll i=1;i<=n;i++)
{
num[i]=sum[n-i+1];//将前缀和数列倒过来求逆序对
if(num[i]>0)//从0到n-i+1位置的子串(前缀)和>0
ans++;
}
merge_s(1,n);
printf("%lld",ans);
return 0;
}