HDU 1394 Minimum Inversion Number(线段树 或 树状数组)

时间:2023-02-05 03:15:25

题目大意:给出从 0 到 n-1 的整数序列,A0,A1,A2...An-1。可将该序列的前m( 0 <= m < n )个数移到后面去,组成其他的序列,例如当 m=2 时,得到序列 A2,A3...An-1,A0,A1 。我们定义逆序对<Ai,Aj>满足 i < j 且Ai > Aj 。 在所有的序列中找出逆序对最少的序列,输出逆序对个数。num[n+1]存储序列元素。

思路: 假设某个序列的逆序对个数为 sum 则下一个序列的逆序对个数为 sum - num[1] + (n - 1) - num[1]。则只需要求出原始序列的逆序对个数计科推出后面的所有序列的逆序对个数。

再输入每个元素的时候统计区间 [num[i]+1,n-1] 之间的元素已经能出现的总次数,则可以用线段树,或树状数组统计。下面给出两种方法的代码。

树状数组:

  #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define INF 0x7fffffff int a[5010],c[5010],n; int lowbit(int x){
return x & (-x) ;
} void add(int x,int d){
while(x <= n){
c[x] += d;
x = x + lowbit(x) ;
}
} int getsum(int x){
int ans = 0;
while(x > 0){
ans += c[x] ;
x = x - lowbit(x) ;
}
return ans ;
} int main(){
int i,j,x,num[5010];
while(~scanf("%d",&n) && n){
int sum = 0;
memset(c,0,sizeof(c));
for(i=1;i<=n;i++){
scanf("%d",&x) ;
num[i] = x ;
x ++ ;
sum += getsum(n) - getsum(x) ;
add(x,1);
}
int ans = sum ;
for(i=1;i<n;i++){
sum = sum - (num[i] + 1) + n - num[i] ;
ans = min(ans,sum);
}
cout << ans << endl;
}
return 0;
}

线段树

  #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define INF 0x7fffffff int n,x;
struct node{
int l,r,sum;
}a[20100]; void buildtree(int i,int l,int r){
a[i].l = l ;
a[i].r = r;
a[i].sum = 0;
if(l == r)
return ;
int mid = (l+r)/2;
buildtree((i<<1),l,mid);
buildtree(i*2+1,mid+1,r);
} int query(int i,int l,int r){
if(l>r)
return 0;
if(a[i].l == l && a[i].r == r)
return a[i].sum;
int sum = 0;
int mid = (a[i].l + a[i].r) / 2 ;
if(r<=mid)
sum = query(i*2,l,r);
else if(l > mid)
sum = query(i*2+1,l,r);
else
sum = query(i*2,l,mid) + query(i*2+1,mid+1,r) ;
return sum ;
} void update(int i,int x){
if(a[i].l == x && a[i].r == x){
a[i].sum ++;
}
else{
a[i].sum ++;
int mid = (a[i].l + a[i].r) / 2 ;
if(x<=mid)
update(i*2,x);
else
update(i*2+1,x);
}
} int main(){
int i,j,sum,num[5010];
while(~scanf("%d",&n) && n ){
sum = 0 ;
buildtree(1,0,n-1);
for(i=1;i<=n;i++){
scanf("%d",&x);
num[i] = x ;
sum += query(1,x+1,n-1);
update(1,x);
}
int ans = sum;
for(i=1;i<n;i++)
{
sum = sum - num[i] + n-num[i]-1 ;
ans = min(ans,sum);
}
cout << ans << endl ;
} return 0;