// [7/29/2014 Sjm] /* 时间复杂度: O(nlogn) 实现方式:树状数组 or 线段树 逆序数: 在一个排列中,若一对数,前面的数大于后一个数(即位置顺序和大小顺序相反),就称它们为一个逆序。排列中,逆序的总数即称为此排列的逆序数。 求逆序数方法: 树状数组 或 线段树 (1)树状数组实现方法:参见 树状数组优化 之 uva299 中的法一 (2)线段树实现方法:在每插入一个数据之前,计算有多少之前插入的数大于它,累计结果,即所要求的逆序数。 但是,由于此题要求所有转换数字串的逆序数,选出最小值,若用 O(n^2logn) 的方法超时。。。故需优化。。。 优化方法(所举例子是指有n个数,从1到n,和题目略有不同): 假设以已求出 a1, a2, ..., an-1, an 排列的逆序数为sum, 若将此数字串转换为 a2, a3, ..., an, a1 则逆序数必然增加 n-a1 (因为此时有 (n-a1) 个比a1大的数在前面), 同时与未转换的字符串相比,逆序数又减少了 (a1-1) 个 (因为此时有 (a1-1) 个比a1小的数在前面) 故而每转换一次后,sum += (n-a1-(a1-1)) 由此可求出答案。。。。(我在做题时,默认将输入的值做 +1 处理)。 */
1 // 树状数组 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 using namespace std; 8 const int MAX_N = 5005; 9 int n, bit[MAX_N], arr[MAX_N]; 10 11 int mySum(int i) { 12 int sum = 0; 13 while (i > 0) { 14 sum += bit[i]; 15 i -= (i&(-i)); 16 } 17 return sum; 18 } 19 20 void myAdd(int i, int x) { 21 while (i <= n) { 22 bit[i] += x; 23 i += (i&(-i)); 24 } 25 } 26 27 void Solve() { 28 memset(bit, 0, sizeof(bit)); 29 int sum = 0; 30 for (int i = 0; i < n; ++i) { 31 sum += (i - mySum(arr[i] + 1)); 32 myAdd(arr[i] + 1, 1); 33 } 34 int ans = sum; 35 for (int i = 0; i < n; ++i) { 36 sum += (n - (arr[i] + 1) - (arr[i] + 1) + 1); 37 ans = min(ans, sum); 38 } 39 printf("%d ", ans); 40 } 41 42 int main() 43 { 44 45 //freopen("input.txt", "r", stdin); 46 //freopen("output.txt", "w", stdout); 47 while (~scanf("%d", &n)) { 48 for (int i = 0; i < n; ++i) { 49 scanf("%d", &arr[i]); 50 } 51 Solve(); 52 } 53 return 0; 54 }
1 // 线段树 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <algorithm> 6 using namespace std; 7 #define lson l, m, rt<<1 8 #define rson m+1, r, rt<<1|1 9 #define GetMid(l, r) l+((r-l)>>1) 10 11 const int MAX_N = 5005; 12 int n, Sum[MAX_N << 2], arr[MAX_N]; 13 14 void PushUp(int rt) { Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1]; } 15 16 void Build(int l, int r, int rt) { 17 if (l == r) { Sum[rt] = 0; return; } 18 int m = GetMid(l, r); 19 Build(lson); 20 Build(rson); 21 PushUp(rt); 22 } 23 24 void Update(int pos, int val, int l, int r, int rt) { 25 if (l == r) { 26 Sum[rt] += val; 27 return; 28 } 29 int m = GetMid(l, r); 30 if (pos <= m) Update(pos, val, lson); 31 else Update(pos, val, rson); 32 PushUp(rt); 33 } 34 35 int Query(int L, int R, int l, int r, int rt) { 36 if (L <= l && r <= R) { return Sum[rt]; } 37 int ans = 0; 38 int m = GetMid(l, r); 39 if (L <= m) ans += Query(L, R, lson); 40 if (m < R) ans += Query(L, R, rson); 41 return ans; 42 } 43 44 int main() 45 { 46 //freopen("input.txt", "r", stdin); 47 //freopen("output.txt", "w", stdout); 48 int sum, ans; 49 while (~scanf("%d", &n)) { 50 Build(1, n, 1); 51 sum = 0; 52 for (int i = 0; i < n; ++i) { 53 scanf("%d", &arr[i]); 54 sum += Query(arr[i] + 1, n, 1, n, 1); 55 int lll = Query(arr[i] + 1, n, 1, n, 1); 56 Update(arr[i] + 1, 1, 1, n, 1); 57 } 58 ans = sum; 59 for (int i = 0; i < n; ++i) { 60 sum += (n - (arr[i] + 1) - (arr[i] + 1) + 1); 61 ans = min(ans, sum); 62 } 63 printf("%d ", ans); 64 } 65 return 0; 66 }