逆序数 POJ 2299 Ultra-QuickSort

 

题目传送门

 1 /*

 2  题意:就是要求冒泡排序的交换次数。  3  逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。  4  一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。  5  如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。也是就说,对于n个不同的元素,  6  先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,  7  当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。  8 

 9  接下来有多种做法求解逆序数:1. 暴力;2. 归并排序;3. 线段树-单点更新;4. 树状数组 10 */
 1 /*

 2  暴力 超时 O(n^2)  3 */

 4 #include <stdio.h>

 5 

 6 const int MAX_N = 500000;  7 int a[MAX_N+10];  8 long long cnt = 0;  9 

10 int main(void)        //POJ 2299 Ultra-QuickSort

11 { 12     //freopen ("inD.txt", "r", stdin);

13     int n; 14     

15     while (scanf ("%d", &n) != EOF && n) 16  { 17         for (int i=1; i<=n; ++i) 18  { 19             scanf ("%d", &a[i]); 20  } 21 

22         for (int i=1; 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         printf ("%lld\n", cnt); 31         cnt = 0; 32  } 33     

34     return 0; 35 }
暴力 超时 O(n^2)
 1 /* 

 2  归并排序是将数列a[p, r]分成两半a[p, q]和a[q+1,r]分别进行归并排序,  3  然后再将这两半合并起来。在合并的过程中(设p<=i<=q,q+1<=j<=r),  4  当L[i]<=R[j]时,并不产生逆序数;  5  当L[i]>R[j]时,在前半部分中比L[i]大的数都比R[j]大,  6  将R[j]放在L[i]前面的话,逆序数要加上q+1-i。  7  因此,可以在归并排序中的合并过程中计算逆序数。  8  

 9  这道题充分印证了,即使merge本身可能用的不多,但分冶的思想却是无所不在:) 10 */

11 #include <stdio.h>

12 

13 const int MAX_N = 500000; 14 const int INF = 0xffffff; 15 int a[MAX_N+10]; 16 long long cnt = 0; 17  

18 void Merge(int *a, int p, int q, int r) 19 { 20     int n1 = q - p + 1; 21     int n2 = r - q; 22     int L[MAX_N/2+1], R[MAX_N/2+1]; 23     int i, j; 24     for (i=1; i<=n1; ++i)    L[i] = a[p+i-1]; 25     for (j=1; j<=n2; ++j)    R[j] = a[q+j]; 26     L[n1+1] = INF;    R[n2+1] = INF; 27 

28     i = 1;    j = 1; 29     for (int k=p; k<=r; ++k) 30  { 31         if (L[i] <= R[j]) 32  { 33             a[k] = L[i++]; 34  } 35         else

36  { 37             a[k] = R[j++]; 38             cnt += n1 - i + 1;         //此步骤是在归并排序法中加的一句,用来计数求逆序数的数目

39  } 40  } 41 } 42 

43 void MergeSort(int *a, int p, int r) 44 { 45     int q; 46     if (p < r) 47  { 48         q = (p + r) / 2; 49  MergeSort (a, p, q); 50         MergeSort (a, q+1, r); 51  Merge (a, p, q, r); 52  } 53 } 54 

55 int main(void)        //POJ 2299 Ultra-QuickSort

56 { 57     //freopen ("inD.txt", "r", stdin);

58     int n; 59     

60     while (scanf ("%d", &n) != EOF && n) 61  { 62         for (int i=1; i<=n; ++i) 63  { 64             scanf ("%d", &a[i]); 65  } 66         MergeSort (a, 1, n); 67         printf ("%lld\n", cnt); 68         cnt = 0; 69  } 70     

71     return 0; 72 }
归并排序
 1 /*

 2  线段树-单点更新  3 */

 4 #include <cstdio>

 5 #include <algorithm>

 6 #define lson l, m, rt << 1

 7 #define rson m+1, r, rt << 1 | 1

 8 using namespace std;  9 

10 const int MAX_N = 500000; 11 const int INF = 0x3f3f3f3f; 12 int a[MAX_N]; 13 int b[MAX_N]; 14 int sum[MAX_N << 2]; 15 

16 void pushup(int rt) 17 { 18     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 19 } 20 

21 void build(int l, int r, int rt) 22 { 23     sum[rt] = 0; 24     if (l == r) return ; 25     int m = (l + r) >> 1; 26  build (lson); 27  build (rson); 28 

29  pushup (rt); 30 } 31 

32 void update(int p, int l, int r, int rt) 33 { 34     if (l == r) 35  { 36         sum[rt]++;      //记录次数

37         return ; 38  } 39     int m = (l + r) >> 1; 40     if (p <= m) 41  { 42  update (p, lson); 43  } 44     else

45  update(p, rson); 46  pushup (rt); 47 } 48 

49 int query(int ql, int qr, int l, int r, int rt) 50 { 51     if (ql <= l && r <= qr) 52  { 53         return sum[rt]; 54  } 55     int m = (l + r) >> 1; 56     int ans = 0; 57     if (ql <= m)    ans += query (ql, qr, lson); 58     if (qr > m)     ans += query (ql, qr, rson); 59 

60     return ans; 61 } 62 

63 int BinarySearch(int key, int l, int r) 64 { 65     while (r >= l) 66  { 67         int mid = (l + r) >> 1; 68         if (key == b[mid])    return mid; 69         if (key < b[mid])    r = mid - 1; 70         else    l = mid + 1; 71  } 72 } 73 

74 int main(void) 75 { 76     //freopen ("inD.txt", "r", stdin);

77     int n; 78     while (~scanf ("%d", &n) && n) 79  { 80         build (0, n-1, 1); 81         

82         for (int i=1; i<=n; ++i) 83  { 84             scanf ("%d", &a[i]); 85             b[i] = a[i]; 86  } 87         sort (b+1, b+n+1); 88         long long ans = 0; 89         for (int i=1; i<=n; ++i) 90  { 91             int x = BinarySearch (a[i], 1, n); 92             ans += query (x, n, 1, n, 1); 93             update (x, 1, n, 1); 94  } 95         printf ("%lld\n", ans); 96  } 97 

98     return 0; 99 }
线段树-单点更新

 

你可能感兴趣的:(Quicksort)