ARC075-E-离散化+树状数组(水

题目大意:

给你一个长度为n的序列。问你有多少个子段满足其算数平均和 ≥ k \geq k k.
n ≤ 1 e 5 , k ≤ 1 e 9 n \leq 1e5,k\leq 1e9 n1e5,k1e9

题目思路:

题目条件可以转化为: s u m [ r ] − s u m [ l − 1 ] r − l + 1 ≤ k \frac{sum[r]-sum[l-1]}{r-l+1} \leq k rl+1sum[r]sum[l1]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[l1]+klsum[r]krk.

那么我们将序列直接变成前缀和序列,那么式子本质在求合法点对。

所以我们可以枚举 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值