a

2017 济南综合班 Day 7

 

两个指针L、R

R开始指向恰好[R,n]有不超过k个逆序对的地方

随着L的右移,R指针只会右移

逆序对有2部分

1、L左侧与其他位置形成的逆序对

2、R右侧与其他位置形成的逆序对

用树状数组分别维护这两部分

同时维护当前逆序对个数

每次L右移,新的L会增加与L左侧的逆序对和与R右侧的逆序对

每次R右移,R的消失会减少R右侧的逆序对和与L左侧的逆序对

 

#include<cstdio>
#include<algorithm>
#define N 100012
using namespace std;
int tot;
int a[N],hash[N];
int c1[N],c2[N];
int query1(int x)
{
    int sum=0; while(x) { sum+=c1[x]; x-=x&-x; } return sum;
}
int query2(int x)
{
    int sum=0; while(x) { sum+=c2[x]; x-=x&-x; } return sum;
}
void add1(int x,int y)
{
    while(x<=tot) { c1[x]+=y; x+=x&-x; }
}
void add2(int x,int y)
{
    while(x<=tot) {    c2[x]+=y; x+=x&-x; }
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,k;
    long long ans=0,cnt=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),hash[i]=a[i];
    sort(hash+1,hash+n+1);
    tot=unique(hash+1,hash+n+1)-(hash+1);
    for(int i=1;i<=n;i++) a[i]=lower_bound(hash+1,hash+tot+1,a[i])-hash;
    int R=n;
    while(R>=1)
    {
        add2(a[R],1);
        cnt+=query2(a[R]-1);
        R--; 
    }
    R++;
    for(int L=1;L<n;L++)
    {
        if(L==R)
        {
            cnt=cnt-(L-1-query1(a[R]))-query2(a[R]-1);
            add2(a[R++],-1);
        }
        cnt=cnt+L-1-query1(a[L])+query2(a[L]-1);
        add1(a[L],1);
        while(cnt>k && R<=n )
        {
            cnt=cnt-(L-query1(a[R]))-query2(a[R]-1);
            add2(a[R++],-1);
        } 
        if(cnt<=k) ans+=n-R+1;
    } 
    printf("%I64d",ans);
}
View Code

相关文章:

  • 2021-07-13
  • 2021-11-02
  • 2021-06-26
  • 2021-10-27
  • 2022-01-24
  • 2021-11-09
  • 2022-01-10
  • 2022-02-20
猜你喜欢
  • 2021-08-01
  • 2021-06-14
  • 2021-07-23
  • 2021-07-31
  • 2021-08-07
  • 2021-10-07
  • 2022-02-24
相关资源
相似解决方案