逆序数 之 hdu 1394 Minimum Inversion Number

来源:互联网 发布:sql注入攻击步骤 编辑:程序博客网 时间:2024/06/06 10:57
//  [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;}


0 0
原创粉丝点击