Minimum
Inversion Number
Time Limit:1000MS Memory Limit:32768KB
64bit IO Format:%I64d & %I64u
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
用线段树求逆序对的水题,维护的是区间内整数的个数,每次插入 x 时,查询在 x 的前面比小的数的个数,并计算出比 x 大的数的个数 cnt[x] ,最后将
cnt 累加,即为逆序数;
将队首的数放到队尾后逆序数改变:n-1-a[i], a[i] 为原始序列中第 i 个数的值;
# include <stdio.h>
# include <string.h>
# define N 50010int n, D;
int sum[4 * N], cnt[N], a[N];void update(int i)
{
for (; i ^ 1; i >>= 1)
{
sum[i >> 1] = sum[i] + sum[i ^ 1];
}
}int query(int s, int t)
{
int ret;ret = 0;
s += D-1, t += D+1;
for ( ; s ^ t ^ 1; s >>= 1, t >>= 1)
{
if (~s & 0x1) ret += sum[s+1];
if ( t & 0x1) ret += sum[t-1];
}return ret;
}void init(void)
{
int i;for (D = 1; D < n+2; D <<= 1) ;
memset(sum, 0, sizeof(sum[0])*2*D+5);
memset(cnt, 0, sizeof(cnt[0])*n+5);
memset(a, 0, sizeof(a[0])*n+5);for (i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
cnt[i] = i - 1 - query(0, a[i]);
++sum[a[i]+D], update(a[i]+D);
}
}void solve(void)
{
int rev, i, min;rev = 0;
for (i = 1; i <= n; ++i)
{
rev += cnt[i];
}
min = rev;
for (i = 1; i <= n; ++i)
{
rev += n-1-2*a[i];
if (min > rev) min = rev;
}
printf("%d\n", min);
}int main()
{
while (~scanf("%d", &n))
{
init();
solve();
}return 0;
}
树状数组实现:
#include<stdio.h>
#include<string.h>
#define min(a,b)(a)<(b)?(a):(b);
int v[5002];
int l[5002];
int n;
int lowbit(int x)
{
return (x)&(-x);
}
void update(int pos)
{
while(pos<=n)
{
l[pos]+=1;
pos+=lowbit(pos);
}
}
int getsum(int x)
{
int sum=0;
while(x>0)
{
sum+=l[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
int res,p,i,sum;
while(scanf("%d",&n)!=EOF)
{
sum=0;
memset(l,0,sizeof(l));
for(i=0;i<n;i++)
{
scanf("%d",&v[i]);
v[i]++;
sum+=(getsum(n)-getsum(v[i]));
update(v[i]);
}
res=sum;
for(i=0;i<n;i++)
{
sum+=n-v[i]-v[i]+1;
res=min(res,sum);
}
printf("%d\n",res);
}
return 0;
}
线段数 --- (单点更新、求逆序对),布布扣,bubuko.com