HDU 5775 Bubble Sort

hdu5775Bubble Sort

Problem Description
P is a permutation of the integers from 1 to N(index starting from 1).
Here is the code of Bubble Sort in C++.

for(int i=1;i<=N;++i)
for(int j=N,t;j>i;–j)
if(P[j-1] > P[j])
t=P[j],P[j]=P[j-1],P[j-1]=t;

After the sort, the array is in increasing order. ?? wants to know the absolute values of difference of rightmost place and leftmost place for every number it reached.

Input
The first line of the input gives the number of test cases T; T test cases follow.
Each consists of one line with one integer N, followed by another line with a permutation of the integers from 1 to N, inclusive.

limits
T <= 20
1 <= N <= 100000
N is larger than 10000 in only one case.

Output
For each test case output “Case #x: y1 y2 … yN” (without quotes), where x is the test case number (starting from 1), and yi is the difference of rightmost place and leftmost place of number i.

Sample Input

2
3
3 1 2
3
1 2 3

Sample Output

Case #1: 1 1 2
Case #2: 0 0 0

Hint
In first case, (3, 1, 2) -> (3, 1, 2) -> (1, 3, 2) -> (1, 2, 3)
the leftmost place and rightmost place of 1 is 1 and 2, 2 is 2 and 3, 3 is 1 and 3
In second case, the array has already in increasing order. So the answer of every number is 0.

注意:题目所给的冒泡排序是从右往前扫描的!

它要我们求一个数在上述交换过程中,它能到达最右端和最左端的差的绝对值

解题思路
1.首先一个数在上诉交换过程中能到达最右短的位置为输入时的位置加上输入时的位置后与该位置逆序的个数(右边有比它小的数才能向右交换,否则只能向左)

2.最左的位置怎么求:一个数最后排序后的位置为i,假如输入时它的位置小于i则最左位置为输入时的位置,故最左的位置为min(i,该数输入时的位置)

所以问题就变为求逆序数个数。
树状数组求逆序数:https://www.cnblogs.com/wdvxdr/p/7300717.html

建议这个树状数组求逆序数因为是我写的

AC代码:

//注意本题的冒泡排序是从后往前扫描交换的 
//我们可以先开一个大小为a的最大值的数组t,并用树状数组维护它,每当读入一个数时,将t[a[i]]加上1,然后我们统计t[1]~t[a[i]]的和ans,
//ans - 1(除掉这个数本身)就是在这个数前面有多少个数比它小。
//我们只要用i-ans就可以得出前面有多少数比它大,也就是逆序对的数量。
//注意本题是输入数组是1~n的范围,n<=100000故无需使用离散化
#include<bits/stdc++.h>
using namespace std;
int n;
int tree[100005];//树状数组
int a[100005];//输入数组
int p[100005];//记录输入数的初始位置 
int nixu[100005];//nixu[i]:i后面与之逆序的个数
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int k)
{
	for(int i=x;i<=n;i+=lowbit(i))
	tree[i]+=k;
	return;
}
int ask(int x)//查询前缀和 
{
	int ans=0;
	for(int i=x;i>=1;i-=lowbit(i))
	ans+=tree[i];
	return ans;
}
int main(void)
{
	int t;
	int z=0; 
	scanf("%d",&t);
	while(t--)
	{
		
		scanf("%d",&n);
		for(int i=0;i<=n;i++)
		tree[i]=0;
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),p[a[i]]=i;
		for(int i=n;i>=1;i--){//从右往前遍历,找a[i]右边比他小的个数 
			add(a[i],1);
			nixu[a[i]]=ask(a[i]-1);//前缀和 ,逆序个数 
		}
		printf("Case #%d: ",++z);
		for(int i=1;i<=n;i++){
			printf("%d",abs(p[i]+nixu[i]/*最右的位置*/-min(i,p[i])/*最左*/));
			if(i!=n)
			printf(" ");
			else
			printf("\n");
		}
		//printf("\n");
	}
	return 0;
}
发布了68 篇原创文章 · 获赞 15 · 访问量 9012

猜你喜欢

转载自blog.csdn.net/qq_43791377/article/details/103341071