大意:求一个序列有几个子序列的和小于给定值,里面的数有正有负,序列长度≤200000。
列个式子,其实求的是sum[r]-sum[l-1]<T
sum[r]-T<sum[l-1]
所以我们可以枚举r,然后用树状数组找小于sum[r]-T的数的个数。记得要在树状数组里先加一个0,表示L取1,即从头开始。
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> #include <cstring> using namespace std; const int N=100005; long long n,pre[N],a[N],ans,t[N],T,sum,tp[N]; void add(long long i) {for(;i<N;i+=i&-i) t[i]++;} long long ask(long long i) {long long res=0;for(;i;i-=i&-i) res+=t[i];return res;} int main() { scanf("%lld%lld",&n,&T); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pre[i]=pre[i-1]+a[i],tp[i]=pre[i]; sort(tp+1,tp+2+n); int u=unique(tp+1,tp+2+n)-tp-1; for(int i=0;i<=n;i++) pre[i]=lower_bound(tp+1,tp+1+u,pre[i])-tp; add(pre[0]); for(int i=1;i<=n;i++) { int pos=lower_bound(tp+1,tp+1+u,tp[pre[i]]-T)-tp; if(tp[pos]!=tp[pre[i]]-T) pos--; ans+=i-ask(pos); add(pre[i]); } cout<<ans<<endl; return 0; }