CF650A Watchmen
CF650A Watchmen
题意翻译
给出 nn 对坐标 (x_i,y_i)(x**i,y**i)。求问曼哈顿距离和欧氏距离相等的坐标组 (i,j)(i,j)(1\leq i<j\leq n1≤i<j≤n)有多少对?
1\leq n\leq 2\times 10^5,|x_i|,|y_i|\leq 10^91≤n≤2×105,∣x**i∣,∣y**i∣≤109。
题解:
2020.11.26模拟赛T1 100分场
曼哈顿距离就是水平距离+竖直距离。欧几里得距离(欧氏距离)就是我们正常认知中的直线距离。
此外还有一个切比雪夫距离。因为题里没说,所以不予介绍,大家可以自己查阅相关资料。
可以看出,曼哈顿距离和欧氏距离是三角形斜边直角边的关系,正常来讲,它们是不可能相等的。所以自然而然的就想到,如果相等,必须是水平或竖直在一条线上。那么我们维护一个键值对map,第一维存横坐标,第二维存个数\(n\),最后遍历所有\(map\),答案是每个坐标的\(n\times(n-1)/2\)。
纵坐标同理,清空之后再维护。
于是拍一遍代码之后发现答案大了不少。
错在哪呢?发现坐标会有相等的情况,这样的话会导致在相同位置的不同的点会被统计到贡献里两次。
用一个小容斥就可以解决啦,先统计相等的点的合法点对数tmp,再用刚刚弄出来的ans-tmp即可。
代码:
#include<cstdio>
#include<map>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=2e5+5;
int n,ans,tmp;
struct node
{
int x,y;
}a[maxn];
map<pair<int,int>,int> mp1;
map<int,int> mp;
map<pair<int,int>,int>::iterator it1;
map<int,int>::iterator it;
signed main()
{
// freopen("question.in","r",stdin);
// freopen("question.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
mp1[make_pair(a[i].x,a[i].y)]++;
}
for(it1=mp1.begin();it1!=mp1.end();it1++)
{
int t=it1->second;
tmp+=(t*(t-1)/2);
}
for(int i=1;i<=n;i++)
mp[a[i].x]++;
for(it=mp.begin();it!=mp.end();it++)
{
int t=it->second;
ans+=(t*(t-1)/2);
}
mp.clear();
for(int i=1;i<=n;i++)
mp[a[i].y]++;
for(it=mp.begin();it!=mp.end();it++)
{
int t=it->second;
ans+=(t*(t-1)/2);
}
printf("%lld\n",ans-tmp);
return 0;
}