原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=1394
一:分析
如果求出第一种情况的逆序列,其他的可以通过递推来搞出来,一开始是t[1],t[2],t[3]....t[N],它的逆序列个数是N个,如果把t[1]放到t[N]后面,逆序列个数会减少t[1]个,相应会增加N-(t[1]+1)个 。
那么根据初始给出的序列求出它的逆序对数,然后再通过递推求出其余的。
二:AC代码
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
using namespace std;
struct Node
{
int left;
int right;
int mid;
int num;
};
Node node[1 << 13];
void build(int left, int right, int pos)
{
node[pos].left = left;
node[pos].right = right;
node[pos].mid = (left + right) / 2 + 1;
node[pos].num = 0;
if (left == right)
return;
build(left, (left + right) / 2, pos * 2);
build((left + right) / 2 + 1, right, pos * 2 + 1);
}
void update(int value, int pos)
{
if (node[pos].left == node[pos].right)
{
node[pos].num = 1;
return;
}
if (value < node[pos].mid)
update(value, pos * 2);
else
update(value, 2 * pos + 1);
node[pos].num = node[pos * 2].num + node[pos * 2 + 1].num;
}
int query(int left, int right, int pos)
{
if (node[pos].left == left&&node[pos].right == right)//注意这里不能写成left==right
return node[pos].num;
if (left < node[pos].mid)
{
if (right < node[pos].mid)
return query(left, right, pos * 2);
else
return query(left, node[pos].mid - 1, pos * 2) + query(node[pos].mid, right, 2 * pos + 1);
}
else
return query(left, right, pos * 2 + 1);
}
int main()
{
int n;
int x;
int sum = 0;
int a[5000];
while (~scanf("%d", &n) && n > 0)
{
build(0, n - 1, 1);
sum = 0;
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
for (int i = 0; i < n; i++)
{
sum += query(a[i], n - 1, 1);
update(a[i], 1);
}
int ans = 99999999;
ans = min(ans, sum);
for (int i = 0; i <= n - 1; i++)
{
sum = sum - a[i] + (n - a[i] - 1);
ans = min(ans, sum);
}
printf("%d\n", ans);
}
return 0;
}