题解 [ABC418E] Trapezium
cjh20090318 · · 题解
卡常题目。
题意
二维平面上有
在所有组合中,以这四点为顶点能组成梯形的组合有多少种?
这里的梯形定义有所不同,平行四边形和矩形都可以认为是梯形。
分析
在任意三点不共线的情况下,相同斜率的任意两条边都可以组成梯形。
为了避免浮点误差以及平行于
但是平行四边形(包括矩形)有两组对边平行,同一个平行四边形会被计算两次。根据平行四边形的判定定理,统计所有的线段的中点,中点位置相同的都可以组成平行四边形。
使用 std::map 维护二元组即可。
时间复杂度 std::unordered_map 做到
代码
//the code is from chenjh
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
int n;
int x[2002],y[2002];
struct FRAC{//分数结构体。
int a,b;//分子和分母。
FRAC(const int _a=0,const int _b=1):a(_a),b(_b){
int g=__gcd(a,b);
a/=g,b/=g,b<0&&(a=-a,b=-b);//保证分母非负,避免比较出现问题。
}
bool operator < (const FRAC&B)const{return (LL)a*B.b<(LL)B.a*b;}//根据分数定义重载小于运算符。
bool operator == (const FRAC&B)const{return a*B.b==B.a*b;}//同上。
};
map<FRAC,int> M;//维护斜率。
map<PII,int> S;//维护中点。
int main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
for(int j=1;j<i;j++)
++M[FRAC(y[i]-y[j],x[i]-x[j])],//计算斜率。
++S[PII(x[i]+x[j],y[i]+y[j])];//中点坐标整体乘 2 避免浮点数运算。
}
LL ans=0;
for(const auto&[a,b]:M) ans+=b*(b-1ll)/2;//对于每一个斜率计算 C(b,2)。
for(const auto&[a,b]:S) ans-=b*(b-1ll)/2;//对于平行四边形类似减去重复答案。
cout<<ans<<'\n';
return 0;
}