飞步A轮笔试题3 子数组的和

 

题目3 : 子数组的和

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

给定一个包含N个整数的数组A = [A1, A2, ... AN],请你计算有多少个子数组B = [Ai, Ai+1, ... Aj] (i ≤ j) 满足B中所有整数的和小于K。

输入

第一行包含两个整数N和K。  

第二行包含N个整数A1, A2, ... AN。  

对于30%的数据,1 ≤ N ≤ 1000  

对于另外30%的数据,0 < Ai ≤ 100000    

对于100%的数据,1 ≤ N ≤ 100000 -100000 ≤ Ai ≤ 100000

输出

一个整数,代表答案。

样例输入

4 -1
-2 1 -2 3

样例输出

3

// 后来才知道是树状数组的模版题

#include <iostream>

#include<stdio.h>

#include<algorithm>

#include<string.h>

#include<vector>

#include<queue>

#include<map>

#include<vector>

typedef long long ll;

const int maxn = 100000;

const int inf = 1e9;

using namespace std;

int n,a[maxn+5];

ll sum[maxn+5], p[maxn+5],K;

int C[maxn+5],num[maxn+5];

int lowbit(int x) {return x&-x;}

int Sum(int x)

{

    int ret = 0;

    while(x>0)

    {

        ret+=C[x];

        x-=lowbit(x);

    }

    return ret;

}

void add(int x,int d)

{

    while(x<=n+1)

    {

        C[x]+=d;

        x+=lowbit(x);

    }

}

int index(ll x)

{

    int l = 0, r = n+1, mid;

    while(r-l>1)

    {

        mid = (l+r)>>1;

        if(p[mid]<=x) l = mid;

        else r = mid;

    }

    return l;

}

int main()

{

    scanf("%d %lld",&n,&K);

    for(int i=1;i<=n;i++)

    {

        scanf("%d",&a[i]);

        sum[i] = sum[i-1] + a[i];

        p[i] = sum[i];

    }

    p[n+1] = 0;

    sort(p+1,p+n+2);

    ll ans = 0;

    add(index(sum[0]),1);

    for(int i=1;i<=n;i++)

    {

        ll w = sum[i] - K;// sum[i] - sum[j] < K, sum[j] > sum[i] - K

        ans+=i - Sum(index(w));

        add(index(sum[i]),1);

    }

    printf("%lld\n",ans);

    return 0;

}

猜你喜欢

转载自blog.csdn.net/weixin_38970751/article/details/83415934