概述
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394
解析:
首先这是到求解逆序数的问题,我们得先知道逆序数是个什么东西?在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
求逆序对数很自然的想到了树状数组,方便又快捷。
对于第一个元素它后面比它小的就一定都会形成逆序对,这样对于当前的逆序对,在第一个元素移至最后时,它的逆序对数就要减少这个元素的值再减去一,因为此题数值是连续的所以可以直接减,而在移至最后时,大于这个元素的数值的数和它都会形成逆序对。这样我们在减了之前的值之后还要加上总的元素的个数减去这个元素的值,这样得到的一个值就是新排列的逆序对数了。例:我们要将a[0]移至末尾,总元素的个数是n,当前的逆序对数是sum,那么将a[0]移至末尾时,sum += N - a[0] - 1 - a[0] 。
有了这个方法,那么我们就可以在O(n)的时间内算出所有排列的最小逆序对数了。总的时间复杂度是O(nlogn)。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN=5005;
#define Lowbit(x) ((x)&(-(x)))
int a[MAXN], c[MAXN];
int N;
void ADD(int p, int val){
while(p>0){
c[p]+=val;
p-=Lowbit(p);
}
}
int getsum(int p){
int sum = 0;
p++;
while(p<=N){
sum += c[p];
p+=Lowbit(p);
}
return sum;
}
int main(){
while(~scanf("%d", &N)){
int i,x;
int sum = 0;
memset(c, 0, sizeof(c));
for(i=0; i<N; ++i){
scanf("%d", &a[i]);
sum += getsum(a[i]+1);
ADD(a[i]+1, 1);
//printf("%dn", sum);
}
int ans = sum;
for(i=0; i<N; ++i){
sum+=(N-1-2*a[i]);
ans = min(ans, sum);
}
printf("%dn", ans);
}
return 0;
}
最后
以上就是害羞凉面为你收集整理的HDU 1394 Minimum Inversion Number(树状数组)的全部内容,希望文章能够帮你解决HDU 1394 Minimum Inversion Number(树状数组)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复