1. 程式人生 > >飛步A輪筆試題3 子陣列的和

飛步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;

}