描述:给定一个序列长n,求多少子串和大于零。
(一开始一定会想到根据前缀和优化,枚举起点和中点O(n)解决)
(那更高效的方法呢?实际上,我们上面就是要求S_i-S_j>0的数量)(S为前缀和数组)
是不是很眼熟?就是一个正序对嘛!归并排序搞一搞。(特殊的,序列长可以为0,另外算)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,s[100009],a[100009],b[100009];
ll ans;
void merge(int l,int mid,int r)
{
int p1=l,p2=mid+1,k=l;
while(p1<=mid&&p2<=r)
{
if(a[p1]<a[p2]) ans+=mid-p1+1,b[k++]=a[p2++];
else b[k++]=a[p1++];
}
while(p1<=mid)
b[k++]=a[p1++];
while(p2<=r)
b[k++]=a[p2++];
for(int i=l;i<=r;i++) a[i]=b[i];
}
void mergesort(int l,int r)
{
if(r>l)
{
int mid=l+r>>1;
mergesort(l,mid);
mergesort(mid+1,r);
merge(l,mid,r);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i],a[i]=a[i-1]+s[i];
for(int i=1;i<=n;i++) if(a[i]>0) ans++;
mergesort(1,n);
cout<<ans;
}
树状数组版本
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+9;
int sumn[maxn],sm[maxn],n,tot;
ll ans;
class Binary_Index_Tree
{
private:
int sumn[maxn];
int lowbit(int x){
return x&(-x);
}
public:
void insert(int x)
{
for(;x<=tot;x+=lowbit(x)) sumn[x]++;
}
int query(int x)
{
int ans=0;
for(;x;x-=lowbit(x)) ans+=sumn[x];
return ans;
}
}bit;
int main()
{
cin>>n;
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
sumn[i]=sumn[i-1]+x;
sm[i]=sumn[i];
}
sort(sm+1,sm+1+n);
tot=unique(sm+1,sm+1+n)-sm-1;
for(int i=1;i<=n;i++)
{
int p=lower_bound(sm+1,sm+tot+1,sumn[i])-sm;
ans+=bit.query(p-1);//搜集1到(p-1)数字
bit.insert(p);
}
for(int i=1;i<=n;i++) if(sumn[i]>0) ans++;
cout<<ans;
}