「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);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章