考虑一个位置上的数字c在冒泡排序过程的变化情况。c会被其后面比c小的数字各交换一次,之后c就会只向前移动。数组从右向左扫,树状数组维护一下得到每个值右边有多少个比其小的值,加上原位置得到最右位置,最左位置为初始位置和最终位置的最小值。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int a[100005];
int b[100005];
int x[100005];
int lowbit(int t)
{
return t&-t;
}
void update(int x)
{
while(x<100005)
{
a[x]++;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x)
{
sum+=a[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
int t;
scanf("%d",&t);
int n,num;
for(int k=1;k<=t;k++)
{
memset(a,0,sizeof(a));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
x[n-i+1]=num;
}
for(int i=1;i<=n;i++)
{
int t=sum(x[i]);//前面比他小的数的个数
//cout<<t<<endl;0 0 2 2 4 5
update(x[i]);
//cout<<t+n-i+1<<endl;//6 5 6 5 6 6
//cout<<min(n-i+1,x[i])<<endl;
b[x[i]]=t+n-i+1-min(n-i+1,x[i]);
//cout<<b[x[i]]<<endl;
}
printf("Case #%d:",k);
for(int i=1;i<=n;i++)
printf(" %d",b[i]);
cout<<endl;
}
return 0;
}