题目意思很明确,每次将序列的第一个元素放到序列尾,产生一个新序列,求出序列中逆序对的个数,一共有n个这种序列,输出其中最小的逆序对个数。先用线段树求解出最原始序列的逆序对的个数,然后递推。
对原始序列的逆序对的个数,在节点信息中添加一个某个区间元素的个数的变量,每次加入新元素的时候,统计当前情况下,其前面的比它大的元素的个数,然后在将元素插入到节点中。递推的时候,由于每次只是将头元素放到尾,所以对于序列中小于头元素的元素的个数都减1 ,同时当其放在尾的时候,它对应的逆序元素的个数为比它大的元素个数。程序如下:
/*
ID: csuchenan
PROG: hduoj 1394 Minimum Inversion Number
LANG: C++
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Mid(x , y) (x + y) / 2
#define MAXN 5005
struct Tree{
int left ;
int right ;
int ncount;
}tree[MAXN * 4] ;
void build(int left , int right , int layer) ;
int query(int left , int right , int layer) ;
void update(int pos , int layer) ;
void work() ;
int n ;
int val[MAXN] ;
int main(int argc , char * argv[]){
while(scanf("%d" , &n)!=EOF){
work() ;
}
return 0 ;
}
void work(){
int i ;
int nval ;
int nsum ;
int nmin ;
nsum = 0 ;
build(0 , n - 1 , 1) ;
for(i = 1 ; i <= n ; i ++){
scanf("%d" , &val[i]) ;
nsum += query(val[i] , n - 1 , 1) ;
update(val[i] , 1) ;
}
nmin = nsum ;
for(i = 1 ; i <= n ; i ++){
nsum = nsum - val[i] + n - val[i] - 1 ;
if(nmin > nsum){
nmin = nsum ;
}
}
printf("%d\n" , nmin) ;
return ;
}
void build(int left , int right , int layer){
tree[layer].ncount = 0 ;
tree[layer].left = left ;
tree[layer].right = right ;
if(left == right){
return ;
}
int llayer = layer * 2 ;
int rlayer = layer * 2 + 1 ;
int mid = Mid(left , right) ;
build(left , mid , llayer) ;
build(mid + 1 , right , rlayer) ;
return ;
}
int query(int left , int right , int layer){
if(tree[layer].left == left && tree[layer].right == right){
return tree[layer].ncount ;
}
int mid = Mid(tree[layer].left , tree[layer].right) ;
int nlayer ;
if(right <= mid){
nlayer = layer * 2 ;
return query(left , right , nlayer) ;
}
if(left > mid){
nlayer = layer * 2 + 1 ;
return query(left , right , nlayer) ;
}
nlayer = layer * 2 ;
return query(left , mid , nlayer ) + query(mid + 1 , right , nlayer + 1) ;
}
void update(int pos , int layer){
tree[layer].ncount ++ ;
if(pos == tree[layer].left && pos == tree[layer].right){
return ;
}
int mid = Mid(tree[layer].left , tree[layer].right) ;
int nlayer = layer * 2 ;
if(pos <= mid){
update(pos , nlayer ) ;
return ;
}
update(pos , nlayer + 1 ) ;
return ;
}

本文介绍了一种使用线段树解决最小逆序数问题的方法。通过递推更新序列的逆序对个数,实现对不同序列变化时逆序对数量的有效计算。
2917

被折叠的 条评论
为什么被折叠?



