题目地址:https://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=1144
#include <cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int MAX=4000000;
const LL M=0xFFFFFFFL;
LL co[MAX];
LL v[MAX];
LL inversion=0;
void invBetween(LL vv[],int lo,int mi,int hi){
int lb=mi-lo;
int lc=hi-mi;
LL *a=vv+lo;
LL *c=vv+mi;
LL *b=new LL[lb];
for(int i=0;i<lb;i++){
b[i]=a[i];
}
for(int i=0,j=0,k=0;j<lb;){
if(lc<=k||b[j]<=c[k]){
a[i++]=b[j++];
}
else{
a[i++]=c[k++];
inversion=inversion+(lb-j);
}
}
delete []b;//有几次提交90,95,就是这个忘了,惭愧
}
void invInside(LL vv[],int lo,int hi){
if(hi-lo<2)return ;
int mi=(lo+hi)>>1;
invInside(vv,lo,mi);
invInside(vv,mi,hi);
invBetween(vv,lo,mi,hi);
}
int main()
{
int n;
LL x,y;
LL c;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld%lld",&x,&y);
co[i]=(x<<28)+y;//10^8小于2^28次方,所以左移了28位,正好7个F。把x和y拼到一起
}
invInside(co,0,n);//x左移28,所以co排序结果跟对x排序是一样的。记得这个调用会改变全局变量inversion。
for(int i=0;i<n;i++){
v[i]=(co[i]&M);//x已经排好序了,把y取出来,求逆序。
}
inversion=0;//好几次忘了把这个逆序重新置零
invInside(v,0,n);
LL N=(LL)n;//直接用n去算n*(n-1)/2,会出错,提交40,45,50分的基本都是这个原因
LL cc=N*(N-1)/2;
printf("%lld\n",cc-inversion);//总对数-逆序对就是互相能照到的灯对。
return 0;
}
哎呀,这么简单,我搞了半天,各种小问题。