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.
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;
}