Hdu 1394 Minimum Inversion Number

≤,≠，≥＜＞

【问题描述】

    The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i  aj.
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:

a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.

a1, a2, ..., an-1, an (当 m = 0 即为原序列不变)
a2, a3, ..., an, a1 (当 m = 1，a1移动到最后)
a3, a4, ..., an, a1, a2 (当m = 2，a1,a2依次移动到最后)
...
an, a1, a2, ..., an-1 （当 m = n-1)



【输入格式】

The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n ≤5000); the next line contains a permutation of the n integers from 0 to n-1.



【输出格式】

For each case, output the minimum inversion number on a single line.



【输入样例1】

10
1 3 6 9 0 8 5 7 4 2


【输出样例1】

16


【参考代码1：使用树状数组】

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
typedef long long ll;
using namespace std;
//freopen("D.in","r",stdin);
//freopen("D.out","w",stdout);
#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
#define maxn 100001
#define mod 10007
#define eps 1e-9
const int inf=0x7fffffff;   //无限大
/*
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
*/
//**************************************************************************************
int d[maxn];
int c[maxn];
int n;
int t;
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int lowbit(int x)
{
return x&-x;
}

void update(int x,int y)
{
while(x<=t)
{
d[x]+=y;
x+=lowbit(x);
}
}
int sum(int x)
{
int s=0;
while(x>0)
{
s+=d[x];
x-=lowbit(x);
}
return s;
}
int num[maxn];
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
memset(c,0,sizeof(c));
int ans=0;
t=n;
for(int i=0;i<n;i++)
{
num[i]++;
ans+=num[i]-sum(num[i]-1)-1;
update(num[i],1);
}
int tmp=ans;
for(int i=0;i<n;i++)
{
tmp+=n-1-2*num[i]+2;
ans=min(tmp,ans);
}
cout<<ans<<endl;
}
}


【参考代码2：使用线段树】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5010;
const int inf=0x3f3f3f3f;
int num[maxn*4];
void buildtree(int le,int ri,int node){
num[node]=0;
if(le==ri) return ;
int t=(le+ri)>>1;
buildtree(le,t,node<<1);
buildtree(t+1,ri,node<<1|1);
}
void update(int pos,int le,int ri,int node){
if(le==ri){
num[node]++;
return ;
}
int t=(le+ri)>>1;
if(pos<=t) update(pos,le,t,node<<1);
else update(pos,t+1,ri,node<<1|1);
num[node]=num[node<<1]+num[node<<1|1];
}
int query(int l,int r,int le,int ri,int node){
if(l<=le&&ri<=r) return num[node];
int t=(le+ri)>>1;
int ans=0;
if(l<=t) ans+=query(l,r,le,t,node<<1);
if(r>t) ans+=query(l,r,t+1,ri,node<<1|1);
return ans;
}
int A[maxn];
int main(){
int n;
while(scanf("%d",&n)!=-1){
int sum=0;
buildtree(1,n,1);//因为是空树，也可以直接memset(num,0,sizeof(num));
for(int i=0;i<n;i++){
scanf("%d",&A[i]);
sum+=query(A[i]+1,n,1,n,1);
//            query(A[i]+1,n,1,n,1)代表的是A[i]+1->n的区间和，如果这之间和为0，
//            代表还没有大于A[i]+1的数出现过，所以逆序数为0;
//            query后的结果如果为k，则说明已经有k个比A[i]+1大的数已经输了
update(A[i]+1,1,n,1);
}
int ans=sum;
for(int i=0;i<n;i++){
sum+=(n-A[i]*2-1);
ans=min(ans,sum);
}
printf("%d\n",ans);
}
return 0;
}