转自:http://wenku.baidu.com/view/6e02b7492e3f5727a5e9623f.html
如何求最小逆序数呢?(我这里假设一个序列中每个数字都不同)
若abcde...的逆序数为k,那么bcde...a的逆序数是多少?我们假设abcde...中小于a的个数为t-1 , 那么大于a的个数就是n - t,当把a移动左移一位时,原来比a大的现在都成了a的逆序对,即逆序数增加n -t,但是原来比a小的构成逆序对的数,现在都变成了顺序,因此逆序对减少 t - 1,所以新序列的逆序数为 k += n - t - t + 1,即k += n + 1 - 2 * t , 于是我们只要不断移位(n次) 然后更新最小值就可以了.
#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int maxn=5010;
int a[maxn],n;
int main(){
while (scanf("%d",&n)==1)
{
for (int i=0;i<n;++i)scanf("%d",&a[i]);
int sum=0,ans=INT_MAX;
for (int i=0;i<n;++i)
{
for (int j=0;j<i;++j)
{
if(a[j]>a[i])sum++;
}
}
for (int i=0;i<n;++i)
{
sum=sum+(n-a[i])-(a[i]+1);
if(sum<ans)ans=sum;
}
printf("%d\n",ans);
}
return 0;
}
线段树解法:读入a[i]的时候,在线段树中查询a[i]-n的值是否存在,存在的话说明在a[i]之前插入了a[i]-n的值,构成了逆序对,然后跟上面的公式一样递推出来
#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int maxn=5010;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int segs[maxn<<2];
void pushUp(int rt){
segs[rt]=segs[rt<<1]+segs[rt<<1|1];
}
void build(int l,int r,int rt){
segs[rt]=0;
if(l==r)return;
int m=(l+r)>>1;
build(lson),build(rson);
pushUp(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R)return segs[rt];
int m=(l+r)>>1,ret=0;
if(L<=m)ret+=query(L,R,lson);
if(R>m)ret+=query(L,R,rson);
return ret;
}
void update(int p,int l,int r,int rt){
if(l==r){
segs[rt]++;
return;
}
int m=(l+r)>>1;
if(p<=m)update(p,lson);
else update(p,rson);
pushUp(rt);
}
int a[maxn],n;
int main(){
while (scanf("%d",&n)==1)
{
build(0,n-1,1);
int sum=0,ans=0;
for (int i=0;i<n;++i)
{
scanf("%d",&a[i]);
sum+=query(a[i],n-1,0,n-1,1);
update(a[i],0,n-1,1);
}
ans=sum;
for (int i=0;i<n;++i)
{
sum=sum+(n-a[i])-(a[i]+1);
if(sum<ans)ans=sum;
}
printf("%d\n",ans);
}
return 0;
}