hdu1394_Minimum Inversion Number
2011-04-25 23:32
302 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1394
先对初始队列统计逆序对数,然后再把每个数一个个移到后面统计逆序对数,取最小。
注意,这里因为是n个数的范围是0~n-1,所以可以利用其性质统计逆序对数。
把位于第一位的num[i]移到最后一位,则变化的逆序对数是在上一个序列(即num[i]为第一位的序列)的基础上加上比num[i]大的数的个数,再减去比num[i]小的数的个数(因为num[i]移到最后以后,只能与前面比他大的数构成逆序对,而在上一个序列中与num[i]构成逆序对的在此序列则没办法构成)。
在求原始序列的逆序对数的时候,可以用线段树or树状数组,特别要注意的是,树状数组的下标不能取0!!要不然会进入死循环~~
代码如下:
先对初始队列统计逆序对数,然后再把每个数一个个移到后面统计逆序对数,取最小。
注意,这里因为是n个数的范围是0~n-1,所以可以利用其性质统计逆序对数。
把位于第一位的num[i]移到最后一位,则变化的逆序对数是在上一个序列(即num[i]为第一位的序列)的基础上加上比num[i]大的数的个数,再减去比num[i]小的数的个数(因为num[i]移到最后以后,只能与前面比他大的数构成逆序对,而在上一个序列中与num[i]构成逆序对的在此序列则没办法构成)。
在求原始序列的逆序对数的时候,可以用线段树or树状数组,特别要注意的是,树状数组的下标不能取0!!要不然会进入死循环~~
代码如下:
]/*线段树*/ #include <cstdio> using namespace std; const int N = 5050; int num ; struct SegTree { int left, right, num; }st[N*3]; void build(int left, int right, int idx) { st[idx].left = left; st[idx].right = right; st[idx].num = 0; if (left == right) return; int mid = (left + right) / 2; build(left, mid, idx*2); build(mid+1, right, idx*2+1); } int query(int left, int right, int idx) { if (st[idx].left == left && st[idx].right == right) return st[idx].num; int mid = (st[idx].left + st[idx].right) / 2; if (right <= mid) return query(left, right, idx*2); else if (left > mid) return query(left, right, idx*2+1); else return query(left, mid, idx*2) + query(mid+1, right, idx*2+1); } void update(int id, int idx) { st[idx].num++; if (st[idx].left == st[idx].right) return; int mid = (st[idx].left + st[idx].right) / 2; if (id <= mid) update(id, idx*2); else update(id, idx*2+1); } void update_min(int &a, int b) { if (a > b) a = b; } int main() { int n; while (scanf("%d", &n) != EOF) { build(0, n-1, 1); int sum = 0; for (int i = 0; i < n; i++) { scanf("%d", &num[i]); sum += query(num[i], n - 1, 1); update(num[i], 1); } int ans = sum; for (int i = 0; i < n; i++) { //上一个序列的逆序对数加上比num[i]大的(num[i]放到最后一个位置后,能与前面每一个比它大的构成逆序对)再减去比num[i]小的 sum = sum + (n - 1 - num[i]) - num[i]; update_min(ans, sum); } printf("%d/n", ans); } }
]/*树状数组*/ #include <cstdio> #include <cstring> using namespace std; class BinaryIndexedTrees { public: static const int BIT_Len = 5050; int t[BIT_Len]; void clear() { memset(t, 0, sizeof(t)); } void add(int x, int v) { while (x < BIT_Len) { t[x] += v; x += x & -x; } } int sum(int x) { int s = 0; while (x) { s += t[x]; x -= x & -x; } return s; } int select(int k) { int l = 1, r = BIT_Len - 1; while (l < r) { int mid = (l + r) / 2; if (sum(mid) < k) l = mid + 1; else r = mid; } return l; } }; BinaryIndexedTrees bt; int num[5050]; void update_min(int &a, int b) { if (a > b) a = b; } int main() { int n; while (scanf("%d", &n) != EOF) { bt.clear(); int sum = 0; for (int i = 0; i < n; i++) { scanf("%d", &num[i]); num[i]++; //不能为0!! sum += i - bt.sum(num[i]); //这里也要相应做出改变 bt.add(num[i], 1); } int ans = sum; for (int i = 0; i < n; i++) { sum = sum + (n - num[i]) - (num[i] - 1); //改变too update_min(ans, sum); } printf("%d/n", ans); } }
相关文章推荐
- 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 (线段树 单点更新 求逆序数)
- Minimum Inversion Number HDU - 1394
- 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
- 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(归并排序/线段树)
- 逆序数 之 hdu 1394 Minimum Inversion Number