【DBSDFZOJ 4409】a(离散化+树状数组)

本文介绍了一种解决逆序对计数问题的有效算法。通过离散化输入序列,并使用两个树状数组来分别记录每个元素前后的逆序对数量,从而在O(n log n)的时间复杂度内找到所有子序列中逆序对数量不超过k的组合。
Description

逆序对是一个非常经典的问题,但是逆序对虽然经典,但却是一个非常困难的问题,因为一个序列的逆序对数可能太多了。所以为了简化问题,我们给定一个长度为N的序列z和一个参数k,我们希望知道有多少个(L,R)满足1 <= L < R <= N,且z1, z2, ⋯ , zL, zR, ⋯ , zN的逆序对个数不超过k。

Input

第一行两个整数N, k。
接下来一行N个整数代表序列。

Output

一行一个整数代表答案。

Sample Input 1

3 1
1 3 2

Sample Output 1

3

Sample Input 2

5 2
1 3 2 1 7

Sample Output 2

6

Data Constraint

对于100%的数据,1 <= N <= 10^5, 1 <= zi <= 10^9, k <= 10^18,有部分分。

解题思路

先离散化zi的值,用一个树状数组记录一个数前面比它大的数的个数,另一个树状数组记录一个数后面比它小的数的个数。从1至n-1枚举每一个L,R从2开始,对于每一个L,R向右找到当时逆序对数不超过k的最小值,此时的R~n都可以是可行的R的方案,加入到答案里。显然R是递增的。

代码
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define N 100001
#define LL long long
using namespace std;
int n,b[N+5],a[N+5],tree[2][N+5];
LL k,now=0,ans=0;
inline void add(int x,int num,int opt){
    while(x<=N){
        tree[opt][x]+=num;
        x+=lowbit(x);
    }
}
inline int search(int x,int opt){
    int re=0;
    while(x){
        re+=tree[opt][x];
        x-=lowbit(x);
    }
    return re;
}
int main(){
    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;++i)        scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);unique(b+1,b+n+1);
    for(int i=1;i<=n;++i)    a[i]=lower_bound(b+1,b+n+1,a[i])-b;
    for(int i=n;i>=2;--i){
        now+=search(a[i]-1,1);
        add(a[i],1,1);
    }
    LL R=2;
    for(int i=1;i<=n-1;++i){
        now+=search(N-a[i]-1,0)+search(a[i]-1,1);
        add(N-a[i],1,0);
        while((now>k || R<=i) && R<=n){
            now-=search(N-a[R]-1,0)+search(a[R]-1,1);
            add(a[R],-1,1);
            ++R;
        }
        if(R==n+1)      break;
        ans+=n-R+1;
    }
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值