平均数

平均数

给定一个长为n的正整数串,求有多少个非空字数组的平均数小于k。

N有100000,所以暴力没有多少分……
这道题是lzw大魔王的这套题的第三题,所以肯定是非常难的。
一上午基本一个小时都在想这道题的做法,先是想了DP,然后发现凭我这智商,想出来的方程只比n方优化不到哪里去,无论如何是过不了的
然后就往数据结构那边想,这道题肯定是要维护前缀和的,那么如何高效的地维护前缀和?
我们肯定先是枚举右端点(说来奇怪,今天第二题第三题都是这种类型的),可以用treap来维护。每走一次左路径,就维护一次,ans+=sz[rson]+1,
到叶子节点后再加一下,
BUTTTTTTTTTTT
treap我不会,想不到吧!!!!!!呵呵呵呵呵呵
然后介绍魔鬼的题解

先把每个数都减去K,题目转化为有多少个非空子数组和>=0.
Si表示前i个数的和,相当于对于每个i,询问有多少个j满足 0 <= j < i, Si - Sj >= 0 即Si >= Sj。
将所有的Si离散化后树状数组询问即可。

做完预处理的s数组,可以满足当i>j时,平均数就一定大于k,因为s[i]-s[j]>0,很容易理解的,
树状数组的图如下:
这里写图片描述

因为s[j]包含了s[1]到s[j-1]的和,所以,当是s[j] < s[i]的时候就可以往前找并把所有的能构成条件的加起来即为解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <ctime>
#include <queue>
#include <set>
using namespace std;

#define N 200010
#define M 500010

typedef long long ll;
const int INF = 1 << 30;
const int mod = 1000000007;

int n, k, cnt;
int a[N], c[N];
ll s[N], t[N], b[N];

map<ll, int> mp;

inline int Lowbit(int x){return x & (-x);}

void Insert(int x)
{
    while (x <= cnt)
    {
        c[x]++;
        x += Lowbit(x);
    }
}
int Sum(int x)
{
    int res = 0;
    while (x)
    {
        res += c[x];
        x -= Lowbit(x);
    }
    return res;
}

int main()
{
    freopen("mean.in", "r", stdin);
    freopen("mean.out", "w", stdout);

    ll ans = 0;
    scanf("%d %d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), s[i] = s[i - 1] + a[i];
    for (int i = 0; i <= n; ++i) t[i] = s[i] - 1ll * k * i, b[i] = t[i];
    sort(b, b + n + 1);

    for (int i = 0; i <= n; ++i) if (!mp[b[i]]) mp[b[i]] = ++cnt;
    for (int i = 0; i <= n; ++i) t[i] = mp[t[i]];

    for (int i = 0; i <= n; ++i)
    {
        ans += Sum(t[i]);
        Insert(t[i]);
    }
    cout << ans << endl;
    return 0; 
}

不懂的地方见我下篇 树状数组
【欺骗访客量的无耻做法】

猜你喜欢

转载自blog.csdn.net/beautiful_cxw/article/details/81036910