http://poj.org/problem?id=2299
Ultra-QuickSort
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 55702 | Accepted: 20570 |
Description
![](https://i-blog.csdnimg.cn/blog_migrate/b3530eaa8fa98ef394d3639722240a8c.jpeg)
Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.
Output
For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
Sample Input
5 9 1 0 5 4 3 1 2 3 0
题意:
给定一段序列,问最少需要交换多少次使其变为升序。
思路:
一看题意,铁定的冒泡排序,再一看数据范围,挺大的,注定超时。
其实题目给的好好的,学习新的排序方法,翻了下下个学期的教材,提前了解下归并排序。
教材-> 《数据结构》人民邮电出版社,严蔚敏编著第二版。
其实,首次接触归并,看了一下午还没看出什么,先敲个树状数组的。
用树状数组 AC 后Code 1,再写一次归并排序吧 Code 2。
题目不错,还有前天宇神讲的离散化操作。
树状数组参考自CSDN-----初始化树状数组,从头到尾读入这些数,每读入一个数就更新树状数组,
查看它前面比它小的已出现过的有多少个数记为 ans,
然后用当前位置减去该 ans,就可得到当前数导致的逆序对数。
把所有的加起来就是总的逆序对数。问题是数字虽然唯一,但是是数据范围大,需要离散化处理。
Code 1 --树状数组:
7644K 391MS
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
const int MYDD=1103+5e5;
/* 离散化操作 */
int reflect[MYDD];//存放离散化操作后的值
struct Q {//离散化记录元素元素大小和位置
int ori_value;//original
int ori_position;
} node[MYDD];
bool cmp_val(Q x,Q y) {//结构体按照value的大小升序
return x.ori_value<y.ori_value;//不知道是不是神经蛋一样,今天总忘记 retrun
}
/* 树状数组操作 */
int tree[MYDD];
int LowBit(int x) {
return (-x)&x;
}
void UpDate(int x,int value,int n) {
while(x<=n) {
tree[x]+=value;
x+=LowBit(x);
}
}
int GetSum(int x) {
int ans=0;
while(x>0) {
ans+=tree[x];
x-=LowBit(x);
}
return ans;
}
int main() {
int n;
while(scanf("%d",&n)&&n) {
for(int j=1; j<=n; j++) {
scanf("%d",&node[j].ori_value);
node[j].ori_position=j;
}
sort(node+1,node+1+n,cmp_val);
for(int j=1; j<=n; j++) {//离散化
reflect[node[j].ori_position]=j;
}
LL ans=0;
memset(tree,0,sizeof(tree));
for(int j=1; j<=n; j++) {
UpDate(reflect[j],1,n);
ans=ans+j-GetSum(reflect[j]);
}
printf("%I64d\n",ans);
}
return 0;
}
Code 2:归并排序
3912K
391MS
#include<stdio.h>
#include<cstring>
typedef __int64 LL;
const int MYDD=1103+5e5;
LL ans;
int a[MYDD],b[MYDD];
void Merge(int low,int mid,int high) { //将无序表啊 a[]归并到 b[]
int i=low,j=mid+1,t=0; //*wa_note i=1
while(i<=mid&&j<=high) { //将 a[]中记录由小到大归并到 b[]中
if(a[i]>a[j]) {
b[t++]=a[j++];
ans+=mid-i+1;
} else {
b[t++]=a[i++];
}
}
while(i<=mid)
b[t++]=a[i++]; //剩余的a[low...mid]赋值到 b[] 中
while(j<=high)
b[t++]=a[j++]; //剩余的a[j...high]赋值到 b[] 中
for(int j=0; j<t;j++)
a[low+j]=b[j]; //*wa_note a[low+i]=b[i]
}
void MergingSort(int low,int high) {
if(low<high) {
int mid=(low+high)/2;//当前序列一分为二
MergingSort(low,mid);//对子序列进行递归归并
MergingSort(mid+1,high);
Merge(low,mid,high);//将以上两个序列归并到 b[]
}
}
int main() {
int n;
while(scanf("%d",&n)&&n) {
ans=0;
for(int j=0; j<n; j++) scanf("%d",&a[j]);
MergingSort(0,n-1);//归并排序
printf("%I64d\n",ans);
}
return 0;
}