逆序数 之 hdu 1394 Minimum Inversion Number
2014-07-29 14:42
330 查看
// [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 处理)。 */
// 树状数组 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 5005; int n, bit[MAX_N], arr[MAX_N]; int mySum(int i) { int sum = 0; while (i > 0) { sum += bit[i]; i -= (i&(-i)); } return sum; } void myAdd(int i, int x) { while (i <= n) { bit[i] += x; i += (i&(-i)); } } void Solve() { memset(bit, 0, sizeof(bit)); int sum = 0; for (int i = 0; i < n; ++i) { sum += (i - mySum(arr[i] + 1)); myAdd(arr[i] + 1, 1); } int ans = sum; for (int i = 0; i < n; ++i) { sum += (n - (arr[i] + 1) - (arr[i] + 1) + 1); ans = min(ans, sum); } printf("%d\n", ans); } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); while (~scanf("%d", &n)) { for (int i = 0; i < n; ++i) { scanf("%d", &arr[i]); } Solve(); } return 0; }
// 线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> using namespace std; #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define GetMid(l, r) l+((r-l)>>1) const int MAX_N = 5005; int n, Sum[MAX_N << 2], arr[MAX_N]; void PushUp(int rt) { Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1]; } void Build(int l, int r, int rt) { if (l == r) { Sum[rt] = 0; return; } int m = GetMid(l, r); Build(lson); Build(rson); PushUp(rt); } void Update(int pos, int val, int l, int r, int rt) { if (l == r) { Sum[rt] += val; return; } int m = GetMid(l, r); if (pos <= m) Update(pos, val, lson); else Update(pos, val, rson); PushUp(rt); } int Query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return Sum[rt]; } int ans = 0; int m = GetMid(l, r); if (L <= m) ans += Query(L, R, lson); if (m < R) ans += Query(L, R, rson); return ans; } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); int sum, ans; while (~scanf("%d", &n)) { Build(1, n, 1); sum = 0; for (int i = 0; i < n; ++i) { scanf("%d", &arr[i]); sum += Query(arr[i] + 1, n, 1, n, 1); int lll = Query(arr[i] + 1, n, 1, n, 1); Update(arr[i] + 1, 1, 1, n, 1); } ans = sum; for (int i = 0; i < n; ++i) { sum += (n - (arr[i] + 1) - (arr[i] + 1) + 1); ans = min(ans, sum); } printf("%d\n", ans); } return 0; }
相关文章推荐
- hdu 1394 Minimum Inversion Number -求逆序对的个数- 线段树单节点更新
- hdu1394 Minimum Inversion Number 线段树求逆序数
- HDU-1394 Minimum Inversion Number (逆序数,线段树或树状数组)
- HDU 1394 Minimum Inversion Number (求逆序对数)
- hdu 1394 Minimum Inversion Number 线段树求逆序数
- hdu 1394 Minimum Inversion Number (裸树状数组 求逆序数 && 归并排序求逆序数)
- [hdu]1394 Minimum Inversion Number -- 暴力求逆序、树状数组求逆序、线段树求逆序、归并排序求逆序
- hdu1394 Minimum Inversion Number 最小逆序数 线段树单点更新区间查询
- hdu 1394 Minimum Inversion Number(线段树求逆序对)
- hdu1394 Minimum Inversion Number(求逆序对)
- HDU 1394 Minimum Inversion Number (线段树 求逆序对)
- HDU 1394 Minimum Inversion Number(线段树求逆序对)
- hdu1394 Minimum Inversion Number 逆序数、最小逆序数
- [HDU 1394]Minimum Inversion Number[逆序对][线段树]
- HDU_1394_Minimum Inversion Number_线段树求逆序数
- [HDU] 1394 Minimum Inversion Number [线段树求逆序数]
- 【线段树求逆序数】【HDU1394】Minimum Inversion Number
- HDU 1394 Minimum Inversion Number(线段树/归并排序求逆序对数)
- hdu 1394 Minimum Inversion Number(逆序对数+线段树)
- 【线段树求逆序数】【HDU1394】Minimum Inversion Number