专栏文章

题解 [ABC418E] Trapezium

AT_abc418_e题解参与者 10已保存评论 12

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
12 条
当前快照
1 份
快照标识符
@miobsb0n
此快照首次捕获于
2025/12/02 16:37
3 个月前
此快照最后确认于
2025/12/02 16:37
3 个月前
查看原文
卡常题目。

题意

二维平面上有 NN 个不同的点,保证任意三点不共线。
在所有组合中,以这四点为顶点能组成梯形的组合有多少种?
这里的梯形定义有所不同,平行四边形和矩形都可以认为是梯形。

分析

在任意三点不共线的情况下,相同斜率的任意两条边都可以组成梯形。
为了避免浮点误差以及平行于 yy 轴的特殊情况,斜率可以采用分数表示。
但是平行四边形(包括矩形)有两组对边平行,同一个平行四边形会被计算两次。根据平行四边形的判定定理,统计所有的线段的中点,中点位置相同的都可以组成平行四边形。
使用 std::map 维护二元组即可。
时间复杂度 O(N2logN)O(N^2 \log N),当然也可以通过重载哈希函数使用 std::unordered_map 做到 O(N2)O(N^2)

代码

CPP
//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;
}

评论

12 条评论,欢迎与作者交流。

正在加载评论...