HDU_1394
这个题目可以根据现有的逆序数对,推出其余情况的逆序数对。
我们每次从开头拿走一个元素,就相当于减少了右边比他小的元素的数量这么多个逆序数对,而放到最后就相当于增加了左边比他大的元素的数量这么多个逆序数对,而这些值是可以用线段树与处理出来的。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXD 10000
int N, M, tree[4 * MAXD], left[MAXD], right[MAXD];
struct Point
{
int x, y;
}p[MAXD];
int cmp(const void *_p, const void *_q)
{
Point *p = (Point *)_p, *q = (Point *)_q;
return p->y - q->y;
}
void init()
{
int i, j, k;
for(M = 1; M < 2 * N + 2; M <<= 1);
for(i = 1; i <= N; i ++)
{
scanf("%d", &p[i].y);
p[i].x = i;
p[i + N].y = p[i].y, p[i + N].x = i + N;
}
}
void update(int i)
{
for(; i ^ 1; i >>= 1)
tree[i >> 1] = tree[i] + tree[i ^ 1];
}
int sum(int i, int j)
{
int ans = 0;
for(; i ^ j ^ 1; i >>= 1, j >>= 1)
{
if(~i & 1)
ans += tree[i ^ 1];
if(j & 1)
ans += tree[j ^ 1];
}
return ans;
}
void solve()
{
int i, j, k, ans = 0, min;
qsort(p + 1, 2 * N, sizeof(p[0]), cmp);
memset(tree + 1, 0, sizeof(tree[0]) * 2 * M);
for(i = 1; i <= (N << 1); i ++)
{
++ tree[M + p[i].x], update(M + p[i].x);
if(p[i].x <= N)
right[p[i].x] = sum(M + p[i].x, M + p[i].x + N);
}
memset(tree + 1, 0, sizeof(tree[0]) * 2 * M);
for(i = (N << 1); i >= 1; i --)
{
++ tree[M + p[i].x], update(M + p[i].x);
if(p[i].x <= N)
ans += sum(M, M + p[i].x);
else
left[p[i].x] = sum(M + p[i].x - N, M + p[i].x);
}
min = ans;
for(i = 1; i <= N; i ++)
{
ans = ans - right[i] + left[i + N];
if(ans < min)
min = ans;
}
printf("%d\n", min);
}
int main()
{
while(scanf("%d", &N) == 1)
{
init();
solve();
}
return 0;
}