1 /* 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) 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 } 36 37 /* 38 题目的意思就是要求冒泡排序的交换次数。 39 所用的算法:用归并排序,求逆序数的个数。 40 41 归并排序是将数列a[p, r]分成两半a[p, q]和a[q+1,r]分别进行归并排序, 42 然后再将这两半合并起来。在合并的过程中(设p<=i<=q,q+1<=j<=r), 43 当L[i]<=R[j]时,并不产生逆序数; 44 当L[i]>R[j]时,在前半部分中比L[i]大的数都比R[j]大, 45 将R[j]放在L[i]前面的话,逆序数要加上q+1-i。 46 因此,可以在归并排序中的合并过程中计算逆序数。 47 48 这道题充分印证了,即使merge本身可能用的不多,但分冶的思想却是无所不在 49 50 */ 51 #include <stdio.h> 52 53 const int MAX_N = 500000; 54 int a[MAX_N+10]; 55 long long cnt = 0; 56 57 const int INF = 0xffffff; 58 59 void Merge(int *a, int p, int q, int r) 60 { 61 int n1 = q - p + 1; 62 int n2 = r - q; 63 int L[MAX_N/2+1], R[MAX_N/2+1]; 64 int i, j; 65 for (i=1; i<=n1; ++i) 66 { 67 L[i] = a[p+i-1]; 68 } 69 for (j=1; j<=n2; ++j) 70 { 71 R[j] = a[q+j]; 72 } 73 L[n1+1] = INF; R[n2+1] = INF; 74 i = 1; j = 1; 75 for (int k=p; k<=r; ++k) 76 { 77 if (L[i] <= R[j]) 78 { 79 a[k] = L[i]; 80 i++; 81 } 82 else 83 { 84 a[k] = R[j]; 85 ++j; 86 cnt += n1 - i + 1; //此步骤是在归并排序法中加的一句,用来计数求逆序数的数目 87 88 } 89 } 90 } 91 92 void MergeSort(int *a, int p, int r) 93 { 94 int q; 95 96 if (p < r) 97 { 98 q = (p + r) / 2; 99 MergeSort (a, p, q); 100 MergeSort (a, q+1, r); 101 Merge (a, p, q, r); 102 } 103 } 104 105 int main(void) //POJ 2299 Ultra-QuickSort 106 { 107 //freopen ("inD.txt", "r", stdin); 108 int n; 109 110 while (scanf ("%d", &n) != EOF && n) 111 { 112 for (int i=1; i<=n; ++i) 113 { 114 scanf ("%d", &a[i]); 115 } 116 MergeSort (a, 1, n); 117 printf ("%lld\n", cnt); 118 cnt = 0; 119 } 120 121 return 0; 122 } 123 124 /* 125 线段树-单点更新 126 */ 127 #include <cstdio> 128 #include <algorithm> 129 #define lson l, m, rt << 1 130 #define rson m+1, r, rt << 1 | 1 131 using namespace std; 132 133 const int MAX_N = 500000; 134 const int INF = 0x3f3f3f3f; 135 int a[MAX_N]; 136 int b[MAX_N]; 137 int sum[MAX_N << 2]; 138 139 void pushup(int rt) 140 { 141 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 142 } 143 144 void build(int l, int r, int rt) 145 { 146 sum[rt] = 0; 147 if (l == r) return ; 148 int m = (l + r) >> 1; 149 build (lson); 150 build (rson); 151 152 pushup (rt); 153 } 154 155 void update(int p, int l, int r, int rt) 156 { 157 if (l == r) 158 { 159 sum[rt]++; //记录次数 160 return ; 161 } 162 int m = (l + r) >> 1; 163 if (p <= m) 164 { 165 update (p, lson); 166 } 167 else 168 update(p, rson); 169 pushup (rt); 170 } 171 172 int query(int ql, int qr, int l, int r, int rt) 173 { 174 if (ql <= l && r <= qr) 175 { 176 return sum[rt]; 177 } 178 int m = (l + r) >> 1; 179 int ans = 0; 180 if (ql <= m) ans += query (ql, qr, lson); 181 if (qr > m) ans += query (ql, qr, rson); 182 183 return ans; 184 } 185 186 int BinarySearch(int key, int l, int r) 187 { 188 while (r >= l) 189 { 190 int mid = (l + r) >> 1; 191 if (key == b[mid]) return mid; 192 if (key < b[mid]) r = mid - 1; 193 else l = mid + 1; 194 } 195 } 196 197 int main(void) 198 { 199 //freopen ("inD.txt", "r", stdin); 200 int n; 201 while (~scanf ("%d", &n) && n) 202 { 203 build (0, n-1, 1); 204 205 for (int i=1; i<=n; ++i) 206 { 207 scanf ("%d", &a[i]); 208 b[i] = a[i]; 209 } 210 sort (b+1, b+n+1); 211 long long ans = 0; 212 for (int i=1; i<=n; ++i) 213 { 214 int x = BinarySearch (a[i], 1, n); 215 ans += query (x, n, 1, n, 1); 216 update (x, 1, n, 1); 217 } 218 printf ("%lld\n", ans); 219 } 220 221 return 0; 222 } 223 224 /* 225 树状数组 226 */
时间: 2024-11-05 11:24:45