a
两个指针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); }