http://poj.org/problem?id=2299
此题即为归并排序求逆序数。
1 #include<stdio.h> 2 #include<string.h> 3 const int N=500002; 4 int a[N],temp[N]; 5 long long ans; 6 void merge_arr(int first,int mid,int last)//合并区间 7 { 8 int k = 0; 9 int i = first,n = mid; 10 int j = mid+1,m = last; 11 while(i <= n && j <= m) 12 { 13 if (a[i] <= a[j]) 14 temp[k++] = a[i++]; 15 else 16 { 17 temp[k++] = a[j++]; 18 ans += (mid-i+1);//计算逆序数 19 } 20 } 21 while(i <= n) 22 temp[k++] = a[i++]; 23 while(j <= m) 24 temp[k++] = a[j++]; 25 for (i = 0; i < k; i ++) 26 a[first+i] = temp[i];//将有序的temp[]赋给原数组 27 } 28 void mergesort(int first,int last)//归并排序 29 { 30 if (first < last) 31 { 32 int mid = (first+last)/2; 33 mergesort(first,mid); 34 mergesort(mid+1,last); 35 merge_arr(first,mid,last); 36 } 37 } 38 int main() 39 { 40 int n; 41 while(~scanf("%d",&n)&&n) 42 { 43 ans = 0; 44 for (int i = 0; i < n; i ++) 45 { 46 scanf("%d",&a[i]); 47 } 48 mergesort(0,n-1); 49 printf("%lld ",ans); 50 } 51 return 0; 52 }
同类型的题:
http://poj.org/problem?id=1804
Brainman
题意:给出n个数,只能相邻的两个数交换,问最少交换多少次才能使这n个数递增排列。
思路:求出该序列的逆序数即为最少交换的次数。
法一:直接暴力o(n^2)
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 using namespace std; 5 const int N=1005; 6 7 int a[N]; 8 9 int main() 10 { 11 int t,o = 0; 12 scanf("%d",&t); 13 while(t--) 14 { 15 o++; 16 int n; 17 scanf("%d",&n); 18 for (int i = 0; i < n; i++) 19 scanf("%d",&a[i]); 20 21 int cnt = 0; 22 for (int i = 0; i < n; i++) 23 { 24 for (int j = i+1; j < n; j++) 25 { 26 if (a[i] > a[j]) 27 cnt++; 28 } 29 30 } 31 printf("Scenario #%d: %d ",o,cnt); 32 } 33 return 0; 34 }
法二:归并排序 o(nlogn)
1 #include <stdio.h> 2 #include <string.h> 3 const int N=1002; 4 const int INF = 1<<28; 5 long long ans = 0; 6 void Merge(int *a,int s,int mid,int t) 7 { 8 int lenl= mid-s+1; 9 int lenr = t-mid; 10 int *b = new int[lenl+2]; 11 int *c = new int[lenr+2]; 12 for (int i = 1; i <= lenl; i++) 13 b[i] = a[s+i-1]; 14 b[lenl+1] = INF; 15 for (int i = 1; i <= lenr; i++) 16 c[i] = a[mid+i]; 17 c[lenr+1] = INF; 18 int i = 1 ,j = 1,k = s; 19 while(k <= t) 20 { 21 if (b[i] <= c[j]) 22 a[k++] = b[i++]; 23 else 24 { 25 a[k++] = c[j++]; 26 ans+=lenl-i+1; //计算逆序数 27 } 28 } 29 delete(b); 30 delete(c); 31 } 32 void MergeSort(int *a,int s,int t) 33 { 34 int mid = (s+t)>>1; 35 if(t <= s) 36 return ; 37 MergeSort(a,s,mid); 38 MergeSort(a,mid+1,t); 39 Merge(a,s,mid,t); 40 } 41 int main() 42 { 43 int t,o = 0,a[N],b[N]; 44 scanf("%d",&t); 45 while(t--) 46 { 47 o++; 48 int n; 49 ans = 0; 50 scanf("%d",&n); 51 for (int i = 1; i <= n; i++) 52 scanf("%d",&a[i]); 53 MergeSort(a,1,n); 54 printf("Scenario #%d: %lld ",o,ans); 55 } 56 return 0; 57 }
法三:树状数组 o(nlogn)
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N=2000005; 6 int c[N],a[N],n; 7 struct node 8 { 9 int data; 10 int pos; 11 friend bool operator < (const node a,const node b) 12 { 13 if(a.data==b.data) 14 return a.pos < b.pos; 15 else 16 return a.data < b.data; 17 } 18 } g[N]; 19 int lowbit(int x) 20 { 21 return x&(-x); 22 } 23 void update(int x,int data) 24 { 25 while(x <= N) 26 { 27 c[x]+=data; 28 x+=lowbit(x); 29 } 30 } 31 int sum(int x) 32 { 33 int ans = 0; 34 while(x > 0) 35 { 36 ans+=c[x]; 37 x-=lowbit(x); 38 } 39 return ans; 40 } 41 int main() 42 { 43 int t,o = 0; 44 scanf("%d",&t); 45 while(t--) 46 { 47 o++; 48 scanf("%d",&n); 49 for (int i = 1; i <= n; i++) 50 { 51 scanf("%d",&g[i].data); 52 g[i].pos = i; 53 } 54 sort(g+1,g+1+n); 55 memset(c,0,sizeof(c)); 56 for (int i = 1; i <= n; i++)//离散化 57 a[g[i].pos] = i; 58 long long ans = 0; 59 for (int i = 1; i <= n; i++) 60 { 61 update(a[i],1); 62 ans+=i-sum(a[i]); 63 } 64 printf("Scenario #%d: %lld ",o,ans); 65 } 66 return 0; 67 }