CF650A Watchmen

CF650A Watchmen

洛谷传送门

题意翻译

给出 nn 对坐标 (x_i,y_i)(x**i,y**i)。求问曼哈顿距离和欧氏距离相等的坐标组 (i,j)(i,j)(1\leq i<j\leq n1≤i<jn)有多少对?

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;
}
posted @ 2020-11-26 13:38  Seaway-Fu  阅读(108)  评论(0编辑  收藏  举报