ZJNU 1712 树状数组

VUDU
Time Limit: 5000MS Memory Limit: 5000K
Total Submissions: 63 Accepted: 23
Description

Young Mirko has been buying voodoo dolls lately. Considering that he is very interested in the cheapest purchase possible, he has been tracking the prices of voodoo dolls each day. His price list consists of doll prices in the last N days, where doll price ai represents the price of a doll i days ago. Mirko thinks he has noticed a connection between the average doll price in a sequence of consecutive days and the price on the following day. He wants to test his hunch and is puzzled by a very interesting question: “For a given P, how many different consecutive subsequences in the last N days are there, when the average doll price was greater than or equal to P?” Two consecutive subsequences are considered different if their beginnings or ends are different.

Input

The first line of input contains the integer N, the sequence length (1 <= N <= 1 000 000). The second line of input contains N prices ai (0 <= ai <= 1 000 000 000). The third line of input contains an integer P. (0 <= P <= 1 000 000 000).

Output

The first and only line of output must contain the answer to Mirko’s question for a given P.

Sample Input
3
1 2 3
3
Sample Output
1

Sample Input
3
1 3 2
2
Sample Output
5

Sample Input
3
1 3 2
3
Sample Output
1

题目链接

题意:给你一个有n个数的集合,让你求有多少个连续的子集,他所有数的平均值大于等于k

解题思路:我们可以先将集合中的每个数都减去k,然后求前缀和,这样,对于第n项,我们只需知道1到n-1项的前缀和有多少个是小于等于它的就可以了。然而如果暴力的话时间复杂度为O(n^2),所以我们可以用树状数组解决这个问题。因为数据过大,所以不能用前缀和作为数组元素,因此还要求用sort和编号进行操作。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
struct node{
    long long sum;
    int bh;
}e[1000001];
long long ans[1000001];
int n;
bool cmp(const node &a,const node &b)
{
    if(a.sum!=b.sum)return a.sum<b.sum;
    return a.bh<b.bh;
}
void update(int x)
{
    while(x<=n+1)
    {
        ans[x]++;
        x+=(x&-x);
    }
}
int Sum(int x)
{
    long long ret=0;
    while(x>0)
    {
        ret+=ans[x];
        x-=(x&-x);
    }
    return ret;
}
int main()
{
    int p;
    scanf("%d",&n);
    long long sum=0;
    for(int i=1;i<=n;i++)
    {
        long long s;
        scanf("%lld",&s);
        e[i].sum=s;
        e[i].bh=i+1;
    }
    scanf("%d",&p);
    e[n+1].sum=0;
    e[n+1].bh=1;
    for(int i=1;i<=n;i++)
    {
        e[i].sum+=e[i-1].sum-p;
    }
    sort(e+1,e+2+n,cmp);
    long long pri=0;
    for(int i=1;i<=n+1;i++)
    {
        pri+=Sum(e[i].bh);
        update(e[i].bh);
    }
    printf("%lld\n",pri);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值