您的位置:首页 > 产品设计 > UI/UE

pku2299 Ultra-QuickSort

2008-10-22 11:00 232 查看
题目意思是求一个序列的逆序数,朴素的做法时间复杂度是O(n^2),其中 n < 500,000 ,结果不用说肯定是超时的;于是思路转向了O(nlogn)的算法,换言之离不开二分、树型结构等方法

这里用到的是杨挺的PDF《树状数组和线段树》里提到的方法:巧妙地将问题转化成类似求RMQ的问题,然后通过树状树组解决

1,将序列离散化,即序列内第k小的元素变成k,注意到题目已说明序列内无相同元素;离散化可通过排序和二分查找解决

2,将b[]初始化为0,遍历离散化后的序列a[1~n],每当向树状数组c[]插入a[i]前,根据c[]用O(logn)的时间求b[1]~b[a[i]]的和,即求得比a[i]先插入且比a[i]小的元素个数(放到序列上理解,就是排在a[i]前面且比a[i]小的元素个数),换算后可得比a[i]先插入且比a[i]大的元素个数,在遍历过程中将其累加到ans,即为答案

3,更新ans后置b[a[i]]为1,同时更新c[]的值(对c[]插入a[i])

排序和统计的复杂度都为O(nlogn),所以算法总复杂度是O(nlogn)

#include <iostream>

#include <algorithm>

using namespace std;

#define MAXN 500005

#define clr(x) memset(x,0,sizeof(x))

int a[MAXN],b[MAXN],c[MAXN],n;

__int64 ans;

int find(int x){

int l=1,r=n,m;

while(r>=l){

m=(l+r)/2;

if(x<b[m])

r=m-1;

else if(x>b[m])

l=m+1;

else

return m;

}

return -1;

}

void discretization(){

int i,t;

for(i=1;i<=n;i++){

t=find(a[i]);

a[i]=t;

}

}

inline int lowbit(int x){

return x&(-x);

}

int sum(int k){//求sum(b[1]~b[k])

int i,res=0;

for(i=k;i>0;i-=lowbit(i))

res+=c[i];

return res;

}

void improve(int k){//插入a[i]后b[a[i]]的值有修改

int i;

//若对b[k]有修改,设影响到了c[p1]、c[p2]、 ,则p1=k,pi+1=pi + lowbit(pi)

for(i=k;i<=n;i+=lowbit(i))

c[i]++;

}

void build(){//建立树状数组c[]

clr(b);

clr(c);

int i,k;

for(i=1;i<=n;i++){

k=a[i];

ans+=i-sum(k)-1;

b[k]=1;

improve(k);

}

}

int main(){

int i;

while(scanf("%d",&n) && n){

for(i=1;i<=n;i++){

scanf("%d",a+i);

b[i]=a[i];

}

sort(b+1,b+n+1);

discretization();//离散化

ans=0;

build();

printf("%I64d\n",ans);

}

return 0;

}

另附合并排序求逆序数代码:

#include <iostream>

#include <algorithm>

using namespace std;

#define MAXN 500001

int a[MAXN],t[MAXN],n;

__int64 ans;

void Merge(int l,int m,int r){

int i=0,j=l,k=m+1;

while(j<=m && k<=r){

if(a[j]>a[k]){

t[i++]=a[k++];

ans+=m-j+1;

}

else

t[i++]=a[j++];

}

while(j<=m)

t[i++]=a[j++];

while(k<=r)

t[i++]=a[k++];

for(j=0;j<i;j++){

a[l+j]=t[j];

}

}

void Mergesort(int l,int r){

if(l<r){

int m=(l+r)/2;

Mergesort(l,m);

Mergesort(m+1,r);

Merge(l,m,r);

}

}

int main(){

int i;

while(scanf("%d",&n) && n){

ans=0;

for(i=0;i<n;i++)

scanf("%d",a+i);

Mergesort(0,n-1);

printf("%I64d\n",ans);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: