「2019 CCPC秦皇岛现场赛A」Angle Beats【哈希 或 二分】

题目连接

题意

  • 就是给你n(n2000)n(n\leq 2000)个整数点,q(q2000)q(q\leq 2000)个询问,每次询问给你一个点p(x,y)p(x,y),求nn个点中有多少点对(u,v)(u,v),使得u,v,pu,v,p三点构成直角三角形,保证所有n+qn+q个点两两互不相同

题解

  • 两种解法:第一种哈希,第二种二分

  • 分两种情况讨论一下

    • pp作为直角
    • pp作为直角三角形当中的一个锐角

    首先需要预处理出所有nn个点两两之间的斜率,要么把用分数表示斜率的分子和分母hashhash,成一个数,要么用一个表示分数的结构体表示即可,然后对于第一种情况,每次询问先预处理出pp与所有nn个点之间的斜率,然后用hashhash或者二分(重载一下结构体即可)去查询与他垂直的点数量,这样一个直角三角形被统计了两次,答案除以22,对于第二种类似处理即可,注意哈希方法过不了hduojhduoj,卡了内存,现场赛是给了两个GG

复杂度

  • 二分(O(q×n×logn))(O(q\times n\times \log n))
  • 哈希(O(q×n×logn))(O(q\times n\times \log n))

代码一(哈希)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+10;
struct point{
    int x,y;
    point(int a=0,int b=0) {x=a;y=b;}
    point operator-(point other) {return point(x-other.x,y-other.y);}
}a[maxn];
int gcd(int a,int b) {return b==0?a:gcd(b,a%b);}
unordered_map<unsigned long long,int>o[maxn],b;
unsigned int Hash(point p) {
    int GCD=gcd(abs(p.x),abs(p.y));
    p.x/=GCD,p.y/=GCD;
    if(p.x<0) {p.x=-p.x;p.y=-p.y;}
    if(p.x==0) p.y=1;
    return (unsigned int)p.x*233334*233334+(unsigned int)p.y*233333;
}
int n,q,x,y;
unsigned int k[maxn];
int main() {
    while(~scanf("%d %d",&n,&q)) {
        for(int i=1;i<=n;i++) scanf("%d %d",&a[i].x,&a[i].y);
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(j!=i) o[i][Hash(a[j]-a[i])]++;
        while(q--) {
            long long ans=0;
            scanf("%d %d",&x,&y);
            for(int i=1;i<=n;i++) k[i]=Hash(point(a[i].y-y,-(a[i].x-x)));
            for(int i=1;i<=n;i++) b[Hash(a[i]-point(x,y))]++;
            for(int i=1;i<=n;i++) ans+=b[k[i]];
            ans/=2;
            for(int i=1;i<=n;i++) ans+=o[i][k[i]];
            printf("%lld\n",ans);
            b.clear();
        }
        for(int i=1;i<=n;i++) o[i].clear();
    }
}

代码二(二分)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+10;
struct point{
    int x,y;
    point(int a=0,int b=0) {x=a;y=b;}
    point operator-(point other) {return point(x-other.x,y-other.y);}
    friend bool operator<(const point &a,const point &b) {
        return 1LL*a.y*b.x<1LL*a.x*b.y;
    }
    friend void init(point &p) {
        if(p.x<0) {p.x=-p.x,p.y=-p.y;}
        if(p.x==0) p.y=1;
    }
}a[maxn],b[maxn],o[maxn][maxn];
int n,x,y,q;
int main() {
    while(~scanf("%d %d",&n,&q)) {
        for(int i=1;i<=n;i++) scanf("%d %d",&a[i].x,&a[i].y);
        for(int i=1;i<=n;i++) { 
            int qwq=0;
            for(int j=1;j<=n;j++) if(j!=i) o[i][++qwq]=(a[j]-a[i]),init(o[i][qwq]);
        }
        for(int i=1;i<=n;i++) sort(o[i]+1,o[i]+n);
        while(q--) {
            scanf("%d %d",&x,&y);
            for(int i=1;i<=n;i++) b[i]=a[i]-point(x,y),init(b[i]);
            sort(b+1,b+n+1);long long ans=0;
            for(int i=1;i<=n;i++) {
                point chuizhi=point(b[i].y,-b[i].x);init(chuizhi);
                ans+=upper_bound(b+1,b+n+1,chuizhi)-lower_bound(b+1,b+n+1,chuizhi);
            }
            ans/=2;
            for(int i=1;i<=n;i++) {
                point chuizhi=point(y-a[i].y,-(x-a[i].x));init(chuizhi);
                ans+=upper_bound(o[i]+1,o[i]+n,chuizhi)-lower_bound(o[i]+1,o[i]+n,chuizhi);
            }
            printf("%lld\n",ans);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章