昨日在hihoCoder看到一题有关逆序对的赛题,题目大概是某个游戏中玩家拥有N艘船只,这些船只等级和火力并不挂钩,也就是说等级高的船只火力并不一定高。所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况。现在将按照等级高低的顺序给出所有船的火力值,请你计算出一共有多少对船满足上面提到的这种情况。
输入
第1行:1个整数N。N表示舰船数量, 1≤N≤100,000
第2行:N个整数,第i个数表示等级第i低的船的火力值a[i],1≤a[i]≤2^31-1。
输出
第1行:一个整数,表示有多少对船满足“A船比B船等级高,但是A船火力低于B船”
样例输入
10 1559614248 709366232 500801802 128741032 1669935692 1993231896 369000208 381379206 962247088 237855491
27
用通俗的话来讲,这道赛题就是说给定一个数组A[n],然后找出其中所有的逆序对的个数。最简单的方法就是从头开始遍历,然后每到一个数在和后面所有的数进行对比,这样总的时间复杂度是o(n^2),显然这不能满足高效的要求。仔细想来曾经在剑指offer上看过类似的题目,然后突然豁然开朗,用归并法!下面就开始着手了:
#include <iostream>
using namespace std;
int ReversePairs(int* arr,int n);
int ReversePairCore(int* arr,int* copy,int start,int end);
int main()
{
int n;
int a[100000];
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int result=ReversePairs(a,n);
cout<<result<<endl;
}
return 0;
}
int ReversePairs(int* arr,int n)
{
if(arr == NULL || n < 0)
return 0;
int* copy=new int[n];
for(int i=0;i<n;i++)
{
copy[i]=arr[i];
}
int count=ReversePairCore(arr,copy,0,n-1);
delete [] copy;
return count;
}
int ReversePairCore(int* arr,int* copy,int start,int end)
{
if(start==end)
{
copy[end]=arr[end];
return 0;
}
int length=(end-start)/2;
int left=ReversePairCore(copy,arr,start,start+length);
int right=ReversePairCore(copy,arr,start+length+1,end);
int i=start+length;
int j=end;
int count=0;
int temp=end;
while(i >= start && j >= start+length+1)
{
if(arr[i]>arr[j])
{
copy[temp--]=arr[i--];
count +=j-length-start;
}
else
{
copy[temp--]=arr[j--];
}
}
for(;i>=start;i--)
{
copy[temp--]=arr[i];
}
for(;j>=start+length+1;j--)
{
copy[temp--]=arr[j];
}
return left+right+count;
}
提交上去的结果却是80/100分,思来想去,怎么也想不出为什么!期初想难道是要数组中的值可能会越界?然后把数组的类型都改为long long int,结果还是不行。后来干脆把所有int都换为long long int,结果通过了!然后大为惊奇,突然发现根结原来在count这个函数返回值上,也就是说,A[N]数组中,1≤N≤100,000,当N=100000,若A[N]已为升序,那么逆序对总个数count=N*(N-1)/2=4999950000>2147483647=2^31-1,越界了!也就是说count必须为long long int才能保证不越界。通过此题,然我很是感慨,对于某些边界条件一定要多加警惕,特别是隐性的边界条件。