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 ", cnt); 31 cnt = 0; 32 } 33 34 return 0; 35 }
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 ", 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 ", ans); 96 } 97 98 return 0; 99 }