Ultra-QuickSort
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 42087 | Accepted: 15296 |
Description
In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4 ,
Ultra-QuickSort produces the output
0 1 4 5 9 .
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
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
Sample Output
6 0/* 之前用归并排序做,竟然超时。。。。很郁闷,明明可以的,,我也没再写归并排序,这个事树状数组做的、 加油!!! Time:2014-9-2 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAX=500005; struct Node{ int val; int pos; }node[MAX]; int C[MAX],hash[MAX],N; bool cmp(const Node a,const Node b){ if(a.val==b.val) return a.pos<b.pos;//因为位置从小到大开始检索,将位置大的放到后边避免重复 return a.val<b.val;//此处排序不能等于,如果值相等,位置按从小到大 } int lowbit(int x){ return x&(-x); } void Modify(int x,int v){ while(x<=N){ C[x]+=v; x+=lowbit(x); } } int nSum(int x){ int sum=0; while(x>0){ sum+=C[x]; x-=lowbit(x); } return sum; } void solve(){ while(scanf("%d",&N),N){ for(int i=1;i<=N;i++){ scanf("%d",&node[i].val); node[i].pos=i;//标记值的位置 } sort(node+1,node+N+1,cmp);//值相等时,位置小的在前,检索的时候按位置从小到大检索, //如果位置从大到小,相同值的时候检索后边的时候会少掉前边的,这样求出来的i-nSum(hash[i])就会多一个,因为位置比它小的还没加到里边,树状数组是按位置来相加的 for(int i=1;i<=N;i++) hash[node[i].pos]=i;//将值位置标记为对应的hash值,将价值离散化,将把原来的位置按价值排序后的顺序进行标记,下边找逆序对的时候按原来的位置进行寻找 for(int i=1;i<=N;i++) C[i]=0; long long ans=0; for(int i=1;i<=N;i++){// i 表示位置,从第一个开始 Modify(hash[i],1); ans+=i-nSum(hash[i]);//排序方式可以使相同的值求逆序对为 0,将其减掉 //hash[i]表示第 i 个位置的hash值,用 i 减之前位置小于等于它的个数,就是比它大的个数 } printf("%lld\n",ans); } } int main(){ solve(); return 0; }
/* 以下为NYOJ117 的代码,代码一样 很费解的是,昨天写的归并排序代码,超时。。。。至今不知道为什么 Time:2014-9-3 0:09 */ #include<cstdio> #include<cstring> #include<climits> #include<algorithm> using namespace std; const int MAX=500000+20; int a[MAX<<1],t1[MAX],t2[MAX]; long long ans; void merge(int start,int end,int mid){ int i,j,k; for(k=0,i=start;i<=mid;i++) t1[k++]=a[i]; t1[k]=INT_MAX; for(k=0,i=mid+1;i<=end;i++) t2[k++]=a[i]; t2[k]=INT_MAX; i=j=0; for(k=start;k<=end;k++){ if(t1[i]<=t2[j]){ a[k]=t1[i++]; }else{ ans+=(mid-start+1-i); a[k]=t2[j++]; } } } void merge_sort(int start,int end){ if(end>start){ int mid=((start+end)>>1); merge_sort(start,mid); merge_sort(mid+1,end); merge(start,end,mid); } } void solve(){ int T,N; scanf("%d",&T); while(T--){ scanf("%d",&N); for(int i=0;i<N;i++) scanf("%d",&a[i]); ans=0; merge_sort(0,N-1); printf("%lld\n",ans); } } int main(){ solve(); return 0; }
/* 以下为超时代码,,我也不知道为什么。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。无语 */ #include<stdio.h> #include<string.h> #include<limits.h> const int MAX=500020; long long cnt; int a[MAX<<1],t1[MAX],t2[MAX]; void Merge(int start,int mid,int end){ int i,j,k; for(k=0,i=0;i<=mid;i++) t1[k++]=a[i]; t1[k]=INT_MAX; for(k=0,i=mid+1;i<=end;i++) t2[k++]=a[i]; t2[k]=INT_MAX;//将前后的最后一个设成无穷大,到了最后一个如果没有合并完,会一直合并 for(i=j=0,k=start;k<=end;k++){ if(t1[i]<=t2[j]){ a[k]=t1[i++]; }else{ cnt+=(mid-start+1-i); a[k]=t2[j++]; //如果前边比后边的大,由后边那个数与前边集合能组成的逆序对数为包括i--mid的个数 } } } void merge_Sort(int start,int end){ if(end>start){ int mid=(start+end)>>1; merge_Sort(start,mid); merge_Sort(mid+1,end); Merge(start,mid,end); } } void solve(){ int T,N; scanf("%d",&T); while(T--){ scanf("%d",&N); for(int i=0;i<N;i++) scanf("%d",&a[i]); cnt=0; merge_Sort(0,N-1); printf("%lld\n",cnt); } } int main(){ solve(); return 0; }