zoukankan      html  css  js  c++  java
  • Codeforces Round #510 (Div. 2) D. Petya and Array(树状数组)

    D. Petya and Array

    题目链接:https://codeforces.com/contest/1042/problem/D

    题意:

    给出n个数,问一共有多少个区间,满足区间和小于t。

    题解:

    假设目前区间右端点为r,左端点为l,那么由前缀和可得知:sumr-suml-1<t,然后我们再边个形:sumr<t+suml-1,根据这个我们可以发现这有点类似于逆序对。

    然后我们就可以用求解逆序对问题的解法来解这个问题了,这里不同的就是每次前面的加上t大于当前这个数即为一对逆序对。

    我用的树状数组来做的,用树状数组用两种枚举方式,一种是从前往后,另一种是从后往前。

    从前往后的话,如若当前是第i个位置,那么首先要保证前面i-1个数都update了,然后查询前面小于等于它减去t的数有多少,最后用i减去就可以了。

    从后往前的话,如若当前是第i个位置,那么从i到最后一个位置都应插入进去,之后查询有多少个小于它加上r就行了。

    这个题里面0也应该考虑进去,表示从1到x的这个区间。

    代码如下(包含两种方式):

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    ll n,t;
    ll a[N],sum[N],c[N];
    ll lowbit(ll x){
        return x&(-x);
    }
    void upd(ll x,ll b){
        for(;x<=N-2;x+=lowbit(x)) c[x]+=b;
    }
    ll query(ll x){
        ll ans = 0;
        for(;x>0;x-=lowbit(x)) ans+=c[x];
        return ans ;
    }
    int main(){
        scanf("%I64d%I64d",&n,&t);
        ll ans=0;
        for(int i=1;i<=n;i++){
            scanf("%I64d",&a[i]);
            sum[i]=sum[i-1]+a[i];
            a[i]=sum[i];
        }
        sort(sum,sum+n+1);
        /*for(int i=n;i>=0;i--){
            int pos1 = lower_bound(sum,sum+n+1,a[i]+t)-sum;
            int pos2 = lower_bound(sum,sum+n+1,a[i])-sum+1;
            ans+=query(pos1);
            //printf("%d
    ",pos1);
            upd(pos2,1);
        }*/
        for(int i=1;i<=n;i++){
            int pos1 = lower_bound(sum,sum+n+1,a[i-1])-sum+1;
            int pos2 = upper_bound(sum,sum+n+1,a[i]-t)-sum;
            upd(pos1,1);
            ans+=i-query(pos2);
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    UVA11367 Full Tank?
    不均衡样本集问题
    NLP interview
    Linux 指令
    Python 趣题
    Grid Illumination
    动态规划-Minimum Cost to Merge Stones
    Contest 141
    Python join()方法
    Single Number
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10294352.html
Copyright © 2011-2022 走看看