HDU 1394 Minimum Inversion Number

52 篇文章 0 订阅
35 篇文章 0 订阅

Problem Description

The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:

a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)

You are asked to write a program to find the minimum inversion number out of the above sequences.

Input

The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.

Output

For each case, output the minimum inversion number on a single line.

Sample Input

10
1 3 6 9 0 8 5 7 4 2

Sample Output

16


数组可以循环,问最少的逆序对数量是多少。

求出初始情况下的逆序对数量,每次把第一个数移到最后,其实改变的逆序对数之和是n-1对。

树状数组

#include<iostream>  
#include<algorithm>
#include<math.h>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 5005;
const int low(int x){ return (x&-x); }
int A[maxn], n, tot, i, j, f[maxn], k, minn;

void add(int x, int y)
{
	for (int i = x; i <= n; i += low(i)) f[i] += y;
}

int sum(int x)
{
	int t = 0;
	for (int i = x; i > 0; i -= low(i)) t += f[i];
	return t;
}

int main(){
	while (~scanf("%d", &n))
	{
		memset(f, 0, sizeof(f));
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &A[i]);
			A[i + n] = ++A[i];
		}
		tot = 0; minn = maxn * maxn;
		for (int i = 1; i < 2 * n; i++)
		{
			if (i <= n) add(A[i], 1);
			k = sum(n) - sum(A[i]);
			if (i <= n) tot += k; else {
				tot = tot + 2 * k - n + 1;
				minn = min(tot, minn);
			}
		}
		cout << minn << endl;
	}
	return 0;
}

zkw线段树
#include<iostream>  
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 10001;
int n, a[maxn], f[2 * maxn], M, sum, m;

void change(int x, int y)
{
	x += M;		f[x] = y;
	for (x >>= 1; x; x >>= 1) f[x] = f[x + x] + f[x + x + 1];
}

int find(int l, int r)
{
	int tot = 0;
	for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1)
	{
		if (~l & 1) tot += f[l ^ 1];
		if ( r & 1) tot += f[r ^ 1];
	}
	return tot;
}

int main(){
	while (~scanf("%d", &n))
	{	
		memset(f, 0, sizeof(f));
		for (sum = 0, M = 1; M < n; M += M);
		for (int i = 1; i <= n; i++) 
		{ 
			scanf("%d", &a[i]); change(++a[i], 1);
			m = sum += a[i] - find(1, a[i]);
		}
		for (int i = 1; i <= n; i++)
		{
			sum = sum + n + 1 - a[i] - a[i];
			m = min(m, sum);
		}
		cout << m << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值