D. Petya and Array
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Petya has an array aa consisting of nn integers. He has learned partial sums recently, and now he can calculate the sum of elements on any segment of the array really fast. The segment is a non-empty sequence of elements standing one next to another in the array.
Now he wonders what is the number of segments in his array with the sum less than tt. Help Petya to calculate this number.
More formally, you are required to calculate the number of pairs l,rl,r (l≤rl≤r) such that al+al+1+⋯+ar−1+ar<tal+al+1+⋯+ar−1+ar<t.
Input
The first line contains two integers nn and tt (1≤n≤200000,|t|≤2⋅10141≤n≤200000,|t|≤2⋅1014).
The second line contains a sequence of integers a1,a2,…,ana1,a2,…,an (|ai|≤109|ai|≤109) — the description of Petya's array. Note that there might be negative, zero and positive elements.
Output
Print the number of segments in Petya's array with the sum of elements less than tt.
Examples
input
Copy
5 4
5 -1 3 4 -1
output
Copy
5
input
Copy
3 0
-1 2 -3
output
Copy
4
input
Copy
4 -1
-2 1 -2 3
output
Copy
3
Note
In the first example the following segments have sum less than 44:
- [2,2][2,2], sum of elements is −1−1
- [2,3][2,3], sum of elements is 22
- [3,3][3,3], sum of elements is 33
- [4,5][4,5], sum of elements is 33
- [5,5][5,5], sum of elements is −1
一、原题地址
点我传送
二、大致题意
求所有[ l , r ]区间和小于T的这样的区间数量。
三、大致思路
记i点的前缀和为sum[ i ]。那么我们所求的区间实际上是满足 sum[ i ]-sum[ j ]<T (i > j)这样的区间。对这个式子做个变换就是sum[ i ] - T< sum[ j ](i > j)。
那么枚举每一个 i ,只需要更新此时有多少个 j 是符合条件的。快速查找之前有多少个 j 符合条件,这可以用树状数组做到。
四、代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<functional>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long LL;
int gcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); }
int n;
LL ans;
LL T;
LL sum[200005],a[200005],f[200005];
const int maxn = 200005;
LL c[maxn]; //用于处理树状数组
int lowbit(int x)
{
return (x)&(-x);
}
void update_onepos(int pos, LL x) //单点增加x
{
while (pos <= n+1)
{
c[pos] += x;
pos += lowbit(pos);
}
}
LL getsum_onepos(int pos) //区间求和 [1,x]
{
LL sum = 0;
while (pos > 0)
{
sum += c[pos];
pos -= lowbit(pos);
}
return sum;
}
void build()
{
for (int i = 1; i <= n; i++)
{
update_onepos(i, 0);
}
}
int main()
{
scanf("%d %lld", &n, &T);
ans = a[0] = 0;
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
sum[i] = a[i] + sum[i - 1];
f[i] = sum[i];
} //读入&求前缀和
f[0] = 0;
sort(f, f + 1 + n);
build(); //建树
for (int i = 1; i <= n; i++)
{
int pos = lower_bound(f, f + n + 1, sum[i - 1]) - f + 1;//找到前一个元素所处的位置
update_onepos(pos, 1); //插入上一个元素
pos = lower_bound(f, f + 1 + n, sum[i] - T + 1) - f;
ans += (i - getsum_onepos(pos)); //找到当前元素&更新
}
printf("%lld\n", ans);
getchar();
getchar();
}