集训第四周(高效算法设计)A题 Ultra-QuickSort
原题poj 2299:http://poj.org/problem?id=2299
题意,给你一个数组,去统计它们的逆序数,由于题目中说道数组最长可达五十万,那么O(n^2)的排序算法就不要再想了,归并排序~~~
这里列出归并的解法:
#include"iostream"
using namespace std;
const int maxn=500000+10;
int T[maxn];
int a[maxn];
long long sum;
void merge_sort(int *a,int x,int y,int *T)
{
if(y-x>1)
{
int m=x+(y-x)/2;
int p=x,q=m,i=x;
merge_sort(a,x,m,T);
merge_sort(a,m,y,T);
while(p<m||q<y)
{
if(q>=y||(p<m&&a[p]<a[q])) T[i++]=a[p++];
else {sum+=m-p;T[i++]=a[q++];}
}
for(int i=x;i<y;i++) a[i]=T[i];
}
}
int main()
{
int n;
while(cin>>n&&n)
{
sum=0;
for(int i=0;i<n;i++) cin>>a[i];
merge_sort(a,0,n,T);
/* for(int i=0;i<n;i++) cout<<a[i]<<' ';
cout<<endl;*/
cout<<sum<<endl;
}
return 0;
}
贴出一段代码,请找出其中的错误并改正:
#include <iostream> #include <cstdio> using namespace std; const int maxn=5e5+10; int a[maxn],n; int t[maxn]; long long ans; void mergesort(int c[],int b,int e) { if(e-b>1) { int p=(b+e)>>1; int mid=p,begi=b; mergesort(c,b,p); mergesort(c,p,e); int i=0; while(mid<e||begi<p) { if(mid>=e||(begi<p&&(c[begi]<=c[mid]))) t[i++]=c[begi++]; else {ans+=p-begi;t[i++]=c[mid++];} } i=0; for(int j=b;j<=e;j++) c[j]=t[i++]; } } int main() { while(scanf("%d",&n),n!=0) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); ans=0; mergesort(a,1,n+1); printf("%d\n",ans); } return 0; }
改正后:
#include <iostream> #include <cstdio> using namespace std; const int maxn=5e5+10; int a[maxn],n; int t[maxn]; long long ans; void mergesort(int c[],int b,int e) { if(e-b>1) { int p=(b+e)>>1; int mid=p,begi=b; mergesort(c,b,p); mergesort(c,p,e); int i=0; while(mid<e||begi<p) { if(mid>=e||(begi<p&&(c[begi]<c[mid]))) t[i++]=c[begi++]; /*必须严格递增,等于也算是逆序数,因为a[begi]后面的数肯定都会大于a[mid]*/ else {ans+=p-begi;t[i++]=c[mid++];} } i=0; for(int j=b;j<e;j++) c[j]=t[i++]; //j不会到e正如begi不会到mid } } int main() { while(scanf("%d",&n),n!=0) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); ans=0; mergesort(a,1,n+1); printf("%lld\n",ans); //输出长整型必须使用%lld或者%I64d } return 0; }