题目3 : 子数组的和
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个包含N个整数的数组A = [A1, A2, ... AN],请你计算有多少个子数组B = [Ai, Ai+1, ... Aj] (i ≤ j) 满足B中所有整数的和小于K。
输入
第一行包含两个整数N和K。
第二行包含N个整数A1, A2, ... AN。
对于30%的数据,1 ≤ N ≤ 1000
对于另外30%的数据,0 < Ai ≤ 100000
对于100%的数据,1 ≤ N ≤ 100000 -100000 ≤ Ai ≤ 100000
输出
一个整数,代表答案。
样例输入
4 -1 -2 1 -2 3
样例输出
3
// 后来才知道是树状数组的模版题
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<vector>
typedef long long ll;
const int maxn = 100000;
const int inf = 1e9;
using namespace std;
int n,a[maxn+5];
ll sum[maxn+5], p[maxn+5],K;
int C[maxn+5],num[maxn+5];
int lowbit(int x) {return x&-x;}
int Sum(int x)
{
int ret = 0;
while(x>0)
{
ret+=C[x];
x-=lowbit(x);
}
return ret;
}
void add(int x,int d)
{
while(x<=n+1)
{
C[x]+=d;
x+=lowbit(x);
}
}
int index(ll x)
{
int l = 0, r = n+1, mid;
while(r-l>1)
{
mid = (l+r)>>1;
if(p[mid]<=x) l = mid;
else r = mid;
}
return l;
}
int main()
{
scanf("%d %lld",&n,&K);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
p[i] = sum[i];
}
p[n+1] = 0;
sort(p+1,p+n+2);
ll ans = 0;
add(index(sum[0]),1);
for(int i=1;i<=n;i++)
{
ll w = sum[i] - K;// sum[i] - sum[j] < K, sum[j] > sum[i] - K
ans+=i - Sum(index(w));
add(index(sum[i]),1);
}
printf("%lld\n",ans);
return 0;
}