Numbers of interval(前缀和数组+二分)
source:河南理工大学算法协会暑期集训积分赛(二)网络同步赛 E题 点我进入评测机
单点时限: 2.0 sec
内存限制: 512 MB
描述
现在有一个数组,请计算有多少的区间 [ l , r ] ( l ≤ r ) [l, r](l≤r) [l,r](l≤r)满足 ∑ i = l r a i ≥ k ∑^r_{i=l} a_i ≥k ∑i=lrai≥k.
输入格式
第一行输入
n
,
k
(
1
≤
n
,
k
≤
1
0
6
)
n,k(1≤n,k≤10^6)
n,k(1≤n,k≤106).
接下来输入
n
n
n个数,第
i
i
i个数为
a
i
(
1
≤
a
i
≤
1
0
3
)
a_i(1≤a_i≤10^3)
ai(1≤ai≤103).
输出格式
输出满足条件的区间个数
样例
input
3 5
2 3 5
output
4
思路
看到区间问题先想到线段树和树状数组,但枚举区间太费时。
后来想到前缀和数组,然后枚举左区间,二分右区间,就可以快速找出区间个数了。
代码
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define _for(i, a) for(ll i = 0; i < (a); i++)
#define _rep(i, a, b) for(ll i = (a); i<= (b); i++)
using namespace std;
typedef long long ll;
const ll maxn = 1000005;
const ll INF = 0x3f3f3f3f;
ll n;
ll k;
ll a[maxn];
int main() {
scanf("%d%d", &n, &k);
mem(a, 0);
for (ll i = 1; i <= n; i++) {
ll x;
scanf("%d", &a[i]);
a[i] += a[i - 1];
}
ll sum = 0;
_rep(i, 1, n) {
ll ans;
ans = lower_bound(a + 1, a + n + 1, k + a[i - 1]) - a;
if (ans != n + 1) sum += (n - ans + 1);
}
cout << sum << "\n";
return 0;
}