HDOJ 1394 - Minimum Inversion Number
来源:互联网 发布:网络信息安全学报 编辑:程序博客网 时间:2024/06/07 07:21
Advanced Data Structures :: Segment Tree
Description
给你一个长度为n的数列,你每次都可以把第一个元素放到最后一位,成为一个新的数列。
这样不停循环,你就可以得到n种不同的数列。我们知道,对于每个数列都有一个逆序数。
输入初始的数列,输出这n种不同数列的逆序数的最小值。
注意数列的元素是从0到n - 1。
Type
Advanced Data Structures :: Segment Tree
Analysis
对于这道题,因为数列的元素是从0到n – 1,所以我们根据元素的值,就可以知道,这个元素An在数列中是第几大的,比它小的有An个,比它大的有n – An – 1个。我们可以先计算出初始数列的逆序数,然后去计算把第一个元素移到最后,逆序数数值的变化。
可以想到,把第一个数移到最后,逆序数会增加n – An(因为比它大的元素),然后减少An个(因为比它小的元素),最后逆序数数值的变化其实就是增加n – 2An – 1。
这样,我们就可以在知道初始数列逆序数的情况下,用O(n)的时间算出所有逆序数并求最大值。
剩下要做的就是,如何去初始数列求逆序数。
求逆序数的方法有两种,一种是排序,计算移动元素的次数(仅限于移动邻位)。
另外一种,可以对每一个元素,计算之前有多少比它大的元素,也就是去找出所有逆序数对。
第一种方法的时间复杂度和排序的时间复杂度相同,只要在移动元素的时候count一下就可以,常用的是归并排序,时间复杂度O(n lg n)。
而第二种方法,简单去暴力枚举,时间复杂度是O(n^2),但是也有O(n lg n)的方法,就是线段树。
线段树的叶子结点初始化为0,表示该元素还未插入,插入后则赋值为1。
从前到后地去枚举并插入每个元素。
枚举时利用线段树计算比它大的元素有几个已经插入,则可以知道在它前面有多少个比它大的元素。
枚举和计算之后,将这个数插入到线段树中。
这样便可以利用线段树,达到O(n lg n)的时间复杂度,以下代码用的就是这种方法。
Solution
// HDOJ 1394// Minimum Inversion Number// by A Code Rabbit#include <cstdio>#include <cstring>#define LSon(x) (x << 1) #define RSon(x) (x << 1 | 1) const int MAXN = 5002;const int ROOT = 1;struct Seg{ int w;};struct SegTree { Seg node[MAXN << 2]; void Update(int pos) { node[pos].w = node[LSon(pos)].w + node[RSon(pos)].w; } void Build() { memset(node, 0, sizeof(node)); } void Modify(int l, int r, int pos, int x) { if (l == r) { node[pos].w = 1; return; } int m = l + r >> 1; if (x <= m) Modify(l, m, LSon(pos), x); else Modify(m + 1, r, RSon(pos), x); Update(pos); } int Query(int l, int r, int pos, int x, int y) { if (x <= l && r <= y) return node[pos].w; int m = l + r >> 1; int res = 0; if (x <= m) res += Query(l, m, LSon(pos), x, y); if (y > m) res += Query(m + 1, r, RSon(pos), x, y); return res; }};int n;int a[MAXN];SegTree tree;int main() { while (scanf("%d", &n) != EOF) { tree.Build(); int sum = 0; for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); sum += tree.Query(0, n - 1, ROOT, a[i], n - 1); // Query(0, n - 1, 1, a[i] + 1, n - 1) is wrong, because a[i] + 1 is // maybe more than n - 1. tree.Modify(0, n - 1, ROOT, a[i]); } int min = sum; for (int i = 0; i < n - 1; ++i) { sum += n - a[i] - 1; sum -= a[i]; min = sum < min ? sum : min; } printf("%d\n", min); } return 0;}
- HDOJ 1394 Minimum Inversion Number
- HDOJ 1394 Minimum Inversion Number
- HDOJ 1394 - Minimum Inversion Number
- HDOJ 1394 Minimum Inversion Number
- HDOJ 1394 Minimum Inversion Number
- HDOJ 1394 Minimum Inversion Number
- hdoj 1394 Minimum Inversion Number
- HDOJ-1394 Minimum Inversion Number
- hdoj 1394 Minimum Inversion Number
- 【树状数组】 HDOJ 1394 Minimum Inversion Number
- hdoj 1394 Minimum Inversion Number 【线段数】
- hdoj--1394 Minimum Inversion Number(逆序)
- HDOJ 1394 Minimum Inversion Number (逆序数对)
- HDOJ 1394 - Minimum Inversion Number 求逆序对+二分查找
- hdoj 1394 Minimum Inversion Number【线段树求逆序对】
- HDOJ 1394 Minimum Inversion Number【求逆序数】
- HDOJ 1394 Minimum Inversion Number(逆序数 + 线段树)
- hdoj 1394 Minimum Inversion Number 线段树||树状数组||分治
- DAL、DAO、ORM、Active Record辨析
- window 批处理命令
- javaEE 学习资料来源
- NuSOAP调用Web Service出现乱码的解决方法
- 对Jquery+JSON+WebService的一点认识
- HDOJ 1394 - Minimum Inversion Number
- 操作系统——死锁介绍
- php soap扩展
- Unicode字符集下CString与char *转换 (解决中文乱码等)(转)
- 利用mmap /dev/mem 读写Linux内存
- 读 《企业应用架构模式》7 过程 VS 对象
- 【解题报告】 HDU 1102 Constructing Roads -- 并查集 最小生成树 Prime算法
- 百度笔试:给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。 要求:空间复杂度O(1),时间复杂度为O(n)
- DedeCMS 如何增加自定义属性