HDU 1394 (逆序数) Minimum Inversion Number
原来求逆序数还可以用线段树,涨姿势了。
首先求出原始序列的逆序数,然后递推每一个序列的逆序数。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 20000 + 10; 7 8 int n, p, qL, qR; 9 int sum[maxn], a[5000 + 10]; 10 11 void update(int o, int L, int R) 12 { 13 if(L == R) { sum[o]++; return; } 14 int M = (L + R) / 2; 15 if(p <= M) update(o*2, L, M); 16 else update(o*2+1, M+1, R); 17 sum[o] = sum[o*2] + sum[o*2+1]; 18 } 19 20 int query(int o, int L, int R) 21 { 22 if(qL <= L && qR >= R) return sum[o]; 23 int ans = 0; 24 int M = (L + R) / 2; 25 if(qL <= M) ans += query(o*2, L, M); 26 if(qR > M) ans += query(o*2+1, M+1, R); 27 return ans; 28 } 29 30 int main() 31 { 32 //freopen("in.txt", "r", stdin); 33 34 while(scanf("%d", &n) == 1) 35 { 36 memset(sum, 0, sizeof(sum)); 37 38 for(int i = 0; i < n; i++) scanf("%d", &a[i]); 39 int inv = 0; 40 for(int i = 0; i < n; i++) 41 { 42 p = a[i]; 43 qL = a[i]; qR = n - 1; 44 inv += query(1, 0, n - 1); 45 update(1, 0, n - 1); 46 } 47 int ans = inv; 48 for(int i = 0; i < n; i++) 49 { 50 inv = inv + n - a[i]*2 - 1; 51 ans = min(ans, inv); 52 } 53 printf("%d\n", ans); 54 } 55 56 return 0; 57 }
既然要求逆序数了,干脆树状数组,归并排序也都试一试。
由于树状数组lowbit的特点,所以数组下标是从1开始的。但是树状数组要比线段树好写很多。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 5000 + 10; 7 int n; 8 int a[maxn], s[maxn]; 9 10 inline int lowbit(int x) { return x&(-x); } 11 12 int sum(int x) 13 { 14 int ans = 0; 15 while(x > 0) { ans += s[x]; x -= lowbit(x); } 16 return ans; 17 } 18 19 void add(int x, int d) 20 { 21 while(x <= n) { s[x] += d; x += lowbit(x); } 22 } 23 24 int main() 25 { 26 //freopen("in.txt", "r", stdin); 27 28 while(scanf("%d", &n) == 1) 29 { 30 memset(s, 0, sizeof(s)); 31 for(int i = 0; i < n; i++) { scanf("%d", &a[i]); a[i]++; } 32 int inv = 0; 33 for(int i = 0; i < n; i++) 34 { 35 inv += sum(n) - sum(a[i]); 36 add(a[i], 1); 37 } 38 int ans = inv; 39 for(int i = 0; i < n; i++) 40 { 41 inv = inv + n + 1 - a[i]*2; 42 ans = min(ans, inv); 43 } 44 printf("%d\n", ans); 45 } 46 47 return 0; 48 }
下面是归并排序,_(:зゝ∠)_
代码不长,但是感觉还是挺容易写错的。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 5000 + 10; 7 int n, inv; 8 int a[maxn], b[maxn], T[maxn]; 9 10 void MergeSort(int x, int y) 11 { 12 if(y - x > 1) 13 { 14 int m = (x + y) / 2; 15 int p = x, q = m, i = x; 16 MergeSort(x, m); MergeSort(m, y); 17 while(p < m || q < y) 18 { 19 if(q >= y || (p < m && a[p] <= a[q])) T[i++] = a[p++]; 20 else { T[i++] = a[q++]; inv += m - p; } 21 } 22 for(i = x; i < y; i++) a[i] = T[i]; 23 } 24 } 25 26 int main() 27 { 28 //freopen("in.txt", "r", stdin); 29 30 while(scanf("%d", &n) == 1) 31 { 32 for(int i = 0; i < n; i++) { scanf("%d", &a[i]); b[i] = a[i]; } 33 inv = 0; 34 MergeSort(0, n); 35 int ans = inv; 36 for(int i = 0; i < n; i++) 37 { 38 inv = inv + n - 1 - b[i]*2; 39 ans = min(ans, inv); 40 } 41 printf("%d\n", ans); 42 } 43 44 return 0; 45 }