给出一串数是(1~n)的一个排列,问在冒泡排序过程中,每个数会出现的最右端位置和最左端位置的差。
一开始想用归并排序做,但是发现归并和冒泡的交换次数相同,但是每个数出现的位置是不同的。所以归并不可行。
最后发现,由左向右冒泡(题目中给的程序是从右向左冒泡,其实结果一样),每个数向左移动的次数就是其前面比他大的数的个数,而其最左端位置就是(未排序的位置-前移的位置),而每个数的最右端位置就是max(排序后的位置,排序前的位置),因为对于较小的数,它只会往左移,而对于较大的数,它的最右端位置就是其排序后的位置。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstring>
#include<map>
#include<string>
#define maxn 110000
#define LL long long
#define MOD 1000000007
using namespace std;
int tree[maxn];
int L[maxn],R[maxn];
int lowbit(int x)
{
return x&(-x);
}
void update(int pos ,int num,int n)
{
while(pos<=n)
{
tree[pos]+=num;
pos+=lowbit(pos);
}
}
int getsum(int end)
{
int sum=0;
while(end>0)
{
sum+=tree[end];
end-=lowbit(end);
}
return sum;
}
int main()
{
int T,I=1;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;++i)
{
int temp;
scanf("%d",&temp);
update(temp,1,n);
int num=getsum(n)-getsum(temp);
L[temp]=i-num;
R[temp]=max(i,temp);
}
printf("Case #%d:",I++);
for(int i=1;i<=n;++i)
{
printf(" %d",R[i]-L[i]);
}
printf("\n");
}
}