这道题我考试的时候又智障了……考试的时候我想到了离散化+树状数组,想到了逆序处理交点,但是就是没有想到逆序对……所以谁都不知道做题打比赛的时候会犯一些什么神奇的错误,只能平时多加练习,形成一种好的做题习惯,这样才能在关键的时候去避免它……
由于我们只需要考虑直线与直线的交点是否在平板内部,而这样的直线与直线的交点也就相当于这两条直线被平板所截得的两条线段的交点,而这两条线段都是由直线分别与平板的两条直线的交点的 x x 坐标决定( y y 坐标可以根据 x x 解析求得),所以我们先考虑把这些 x x 坐标求出来,不妨设两条直线为:
1. 1. 求出所有的 x,X x , X 。时间复杂度: O(n) O ( n )
2. 2. 按照 x x 从小到大排序并编号。时间复杂度: O(nlog2n) O ( n l o g 2 n )
3. 3. 按照 X X 从小到大排序并求出此时编号的逆序对数。 O(nlog2n) O ( n l o g 2 n )
总的时间复杂度: O(nlog2n) O ( n l o g 2 n )
参考代码:
#include
#include
#include
#include
#include
#define DB double
#define SG string
#define LL long long
#define LowBit(X) (X&(-X))
using namespace std;
const LL Max=1e5+5;
const LL Mod=1e9+7;
const LL Inf=1e18;
struct Node{
LL K,B,ID;
DB X1,X2;
}G[Max];
LL K,A,B,N,Ans,Bit[Max];
inline LL Read(){
LL X=0;char CH=getchar();bool F=0;
while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
return F?-X:X;
}
inline void Write(LL X){
if(X<0)X=-X,putchar('-');
if(X>9)Write(X/10);
putchar(X%10+48);
}
bool Cmp1(Node P,Node Q){
return P.X1bool Cmp2(Node P,Node Q){
return P.X2void Update(LL X,LL Y){
for(;X<=N;X+=LowBit(X)){
Bit[X]+=Y;
}
}
LL GetSum(LL X){
LL Sum=0;
for(;X;X-=LowBit(X)){
Sum+=Bit[X];
}
return Sum;
}
int main(){
LL I,J,K;
K=Read(),A=Read(),B=Read();
N=Read();
for(I=1;I<=N;I++){
G[I].K=Read(),G[I].B=Read();
G[I].X1=(G[I].B*1.0-B*1.0)/(K*1.0-G[I].K*1.0);
G[I].X2=(G[I].B*1.0-A*1.0)/(K*1.0-G[I].K*1.0);
}sort(G+1,G+1+N,Cmp1);
for(I=1;I<=N;I++){
G[I].ID=I;
}sort(G+1,G+1+N,Cmp2);
for(I=1;I<=N;I++){
Ans+=(GetSum(N)-GetSum(G[I].ID));Update(G[I].ID,1);
}
Write(Ans);
return 0;
}