Atcoder E - Meaningful Mean(线段树+思维)

题目链接:http://arc075.contest.atcoder.jp/tasks/arc075_c

题意:问数组a有多少子区间平均值为k

 

题解:一开始考虑过dp,但是显然不可行,其实将每一个数都减去k就不用求平均值了,然后就是求满足前缀和sum[r]-sum[l-1]>=0,有多少组就行了。有点像逆序对。

用线段树即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int M = 2e5 + 10;
struct TnT {
    int pos;
    ll val;
}nn[M];
struct node {
    int l , r;
    ll sum;
}T[M << 2];
bool cmp(TnT a , TnT b) {
    if(a.val == b.val) return a.pos < b.pos;
    return a.val < b.val;
}
void push_up(int i) {
    T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
}
void build(int i , int l , int r) {
    int mid = (l + r) >> 1;
    T[i].l = l , T[i].r = r , T[i].sum = 0;
    if(l == r) return ;
    build(i << 1 , l , mid);
    build((i << 1) | 1 , mid + 1 , r);
    push_up(i);
}
void update(int i , int pos) {
    int mid = (T[i].l + T[i].r) >> 1;
    if(T[i].l == pos && T[i].r == pos) {
        T[i].sum++;
        return ;
    }
    if(mid < pos) update((i << 1) | 1 , pos);
    else update(i << 1 , pos);
    push_up(i);
}
ll query(int i , int l , int r) {
    int mid = (T[i].l + T[i].r) >> 1;
    if(T[i].l == l && T[i].r == r) {
        return T[i].sum;
    }
    push_up(i);
    if(mid < l) return query((i << 1) | 1 , l , r);
    else if(mid >= r) return query(i << 1 , l , r);
    else {
        return query(i << 1 , l , mid) + query((i << 1) | 1 , mid + 1 , r);
    }
}
int main() {
    ll n , k , a;
    scanf("%lld%lld" ,  &n , &k);
    for(int i = 1 ; i <= n ; i++) {
        scanf("%lld" , &a);
        a -= k;
        nn[i].pos = i;
        nn[i].val = nn[i - 1].val + a;
    }
    sort(nn + 1 , nn + 1 + n , cmp);
    ll ans = 0;
    build(1 , 1 , (int)n);
    for(int i = 1 ; i <= n ; i++) {
        update(1 , nn[i].pos);
        if(nn[i].val >= 0) ans++;
        if(nn[i].pos - 1 == 0) continue;
        ans += query(1 , 1 , nn[i].pos - 1);
    }
    printf("%lld\n" , ans);
    return 0;
}

转载于:https://www.cnblogs.com/TnT2333333/p/6943102.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值