ABC418E

题意是给了一些点,让你求出这些点能围成多少个至少有一对边平行的四边形
考虑枚举两条平行的边,把所有边按照斜率分类,第i类有 \(s_i\) 条边,则该类对答案的贡献应为 \(\frac{s_i(s_i-1)}{2}\)
但在统计平行四边形时会重复计数。
考虑去重,可以由平行四边形的判定定理入手。这里我使用的是对边平行且相等,也就是在斜率相同的边中再多统计长度相同的。
这里用 \(map\) 进行存储,插入的需求量较大,实测了 \(map\) 并不如 \(unordered\_map\) 的速度快,不过需要自行写一个哈希函数。
然后复杂度方面,使用 \(map\) 的总体复杂度的是 \(O(n^2log\ n)\)\(unordered\_map\) 的复杂度跟哈希函数有关系比较玄学,但是理论上插入应该是常数级别,所以总体复杂度是 \(O(n^2)\),玄学常数一般就看数据卡不卡你了,放这题是能过的。

代码如下:

#include<bits/stdc++.h>
#define int long long
#define f first
#define s second
#define PII pair<int,int>
#define re register
using namespace std;
struct node{
	PII p;
	int len;
	friend bool operator<(node a,node b){return a.len^b.len?(a.len<b.len):a.p<b.p;}
	friend bool operator==(node a,node b){return (a.len==b.len)&&(a.p==b.p);}
}z[4000001];
struct hash_pair{
    size_t operator()(const PII&p)const{return hash<int>()(p.first)^(hash<int>()(p.s)<<1);}
};
struct hash_node{
    size_t operator()(const node& n)const{
        size_t h1=hash_pair()(n.p),h2=hash<int>()(n.len);
        return h1^(h2<<1);
    }
};
PII a[10001];
unordered_map<node,int,hash_node>mp2;
unordered_map<PII,int,hash_pair>mp;
int n,ans,cnt,t;
int dist(PII l,PII r){
	int x=(l.f-r.f)*(l.f-r.f),y=(l.s-r.s)*(l.s-r.s);
	return x+y;
}
PII calc(PII l,PII r){
	int p=l.s-r.s,q=l.f-r.f,g=__gcd(p,q);
	if(!g)g=1;
	return make_pair(q/g,p/g); 
} 
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n;
	for(re int i=1;i<=n;i++)cin>>a[i].f>>a[i].s;
	for(re int i=1;i<=n;i++)
		for(re int j=i+1;j<=n;j++){
			node tmp;
			tmp.p=calc(a[i],a[j]),tmp.len=dist(a[i],a[j]);
			ans+=mp[tmp.p],mp[tmp.p]++,t+=mp2[tmp],mp2[tmp]++;
		}
	cout<<ans-t/2;
	return 0;
}

posted @ 2025-08-14 20:49  zhuoheng  阅读(14)  评论(0)    收藏  举报