题目大意:
给你一个长度为n的序列。问你有多少个子段满足其算数平均和
≥
k
\geq k
≥k.
n
≤
1
e
5
,
k
≤
1
e
9
n \leq 1e5,k\leq 1e9
n≤1e5,k≤1e9
题目思路:
题目条件可以转化为: s u m [ r ] − s u m [ l − 1 ] r − l + 1 ≤ k \frac{sum[r]-sum[l-1]}{r-l+1} \leq k r−l+1sum[r]−sum[l−1]≤k
将其转化成: s u m [ l − 1 ] + k l ≤ s u m [ r ] − k r − k sum[l-1]+kl\leq sum[r]-kr-k sum[l−1]+kl≤sum[r]−kr−k.
那么我们将序列直接变成前缀和序列,那么式子本质在求合法点对。
所以我们可以枚举 r r r.查询之前的 l l l满足上式。
经典trick:因为式子的值可能很大,但是可能的取值最多 2 n 2n 2n个。所以将涉及到的式子全部离散化。然后就可以丢到树状数组里维护大小关系了.
这里千万要注意一点:权值线段树和树状数组千万要注意取值域大小,而不是序列长度.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
const int maxn = 6e5 + 5;
const int mod = 1e9 + 7;
ll a[maxn] , n , k;
ll dist[maxn] , cnt , sum[maxn];
int lowbit(int x) {return x & -x;}
void add (int x , ll c)
{
while (x <= cnt){
sum[x] += c;
x += lowbit(x);
}
}
ll ask (ll x)
{
ll ans = 0;
while (x){
ans += sum[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> k;
for (int i = 1 ; i <= n ; i++)
cin >> a[i];
for (int i = 1 ; i <= n ; i++)
a[i] += a[i - 1];
for (ll i = 1 ; i <= n ; i++){
dist[++cnt] = a[i - 1] - k * i;
dist[++cnt] = a[i] - k * i - k;
}
sort(dist + 1 , dist + 1 + cnt);
cnt = unique(dist + 1 , dist + 1 + cnt) - dist - 1;
ll ans = 0;
ll s = lower_bound(dist + 1 , dist + 1 + cnt , -k) - dist;
add(s , 1);
for (ll i = 1 ; i <= n ; i++){
ll now = lower_bound(dist + 1 , dist + 1 + cnt , a[i] - k * i - k) - dist;
ans += ask(now);
add(now , 1);
}
cout << ans << endl;
return 0;
}