日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Boundary(2020多校第二场B)

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Boundary(2020多校第二场B) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Boundary(2020多校第二場B)

文章目錄

    • 題意:
    • 題解:
      • 思路1:
        • 代碼:
      • 思路二
        • 代碼

題意:

坐標平面有n個點(不與原點(0,0)重復),現考慮一個圓,(0,0)點在圓的邊界,問這個圓的邊界上最多能有多少其他的點(不含原點)?
我們看一下樣例:

4 1 1 0 2 2 0 2 2

如圖所示,我們選(0,2)為P,線段op對應的角中,∠PA2O=∠OA3P,說明A2,A3也在圓上,再加上p點,一共是三個,答案就是三

題解:

我一開始是暴力求解,直接枚舉兩個點,再枚舉其他點看在不在邊界上,復雜度是O(n3),但顯然不行

思路1:

原點肯定在邊界,我們可以先枚舉一個點p,原點O與p組成線段op,op是圓上的一個弦,再枚舉其他點A,根據“同弧所對的圓周角相等”,我們計算出∠OAP,然后找到最多數(眾數)即可。但是度數相同不一定在同一個圓上(如圖),會關于OP對稱,我們只需規定A只能在OP下方,這樣就確定位置,即OP(向量) * OA(向量) < 0
時間復雜度O(n2log n)

代碼:

#include <cstdio> #include <algorithm> using namespace std; typedef long long LL; typedef __int128_t LLL; #define N 2000 + 5int n, ans = 1, X[N], Y[N];struct Frac {LL fz, fm;Frac() : Frac(0, 1){}Frac(LL fz, LL fm) : fz(fz), fm(fm) {}bool operator < (const Frac &rhs){return (LLL) fz * rhs.fm < (LLL) fm * rhs.fz;//判斷誰的角大 }bool operator == (const Frac &rhs)//判斷角是否相等 {return (LLL) fz * rhs.fm == (LLL) fm * rhs.fz;} }A[N];int Cross(int lhs, int rhs)//判斷是否平行 {return X[lhs] * Y[rhs] - X[rhs] * Y[lhs]; }int Dis2(int lhs, int rhs)//兩點的距離的平方和 {int dx = X[lhs] - X[rhs], dy = Y[lhs] - Y[rhs];return dx * dx + dy * dy; }int Sgn(int x)//用以調整x的正負 {if (x > 0) return 1;if (x < 0) return -1;return 0; }Frac GetCosAngle2(int i, int j) {int a2 = Dis2(0, i);//求邊 int b2 = Dis2(i, j);int c2 = Dis2(0, j);int sgn = Sgn(b2 + c2 - a2);return Frac(1LL * sgn * (b2 + c2 - a2) * (b2 + c2 - a2), 4LL * b2 * c2);//賦值 //余弦定理 cosA=(b2+c2-a2)/2bc }int main() {scanf("%d", &n);for (int i = 1; i <= n; i ++)scanf("%d%d", X + i, Y + i);for (int i = 1; i <= n; i ++){int cnt = 0;for (int j = 1; j <= n; j ++)if (Cross(i, j) > 0)A[++ cnt] = GetCosAngle2(i, j);sort(A + 1, A + cnt + 1);for (int l = 1, r; l <= cnt; l = r){for (r = l; A[l] == A[r] && r <= cnt; r ++) ;ans = max(ans, r - l + 1);}}printf("%d\n", ans);return 0; }

思路二

任意兩個線段的中垂線的交點作圓心,圓肯定過兩個線段的四個點,又因為必過原點,所以枚舉每一個點,求它與原點所做線段的中垂線,然后求中垂線的所有交點,記錄交點數
也就是求每個三角形的外心
特判中垂線都平行的情況
具體求外心的方法:
a(x1,y1) b(x2,y2) c(x3,y3)
外心o(x,y)
外心是垂直平分線的交點,也就是外心到各點距離相等
(x1-x) * (x1-x)-(y1-y) * (y1-y)=(x2-x) * (x2-x)+(y2-y) * (y2-y);
(x2-x) * (x2-x)+(y2-y) * (y2-y)=(x3-x) * (x3-x)+(y3-y) * (y3-y);
化簡:
2*(x2-x1)x+2(y2-y1)y=x22+y22-x12-y12;
2*(x3-x2)x+2(y3-y2)y=x32+y32-x22-y22;
A1=2*(x2-x1);
B1=2*(y2-y1);
C1=x22+y22-x12-y12;
A2=2*(x3-x2);
B2=2*(y3-y2);
C2=x32+y32-x22-y22;
所以
A1x+B1y=C1;
A2x+B2y=C2;
結論:
x=((C1B2)-(C2B1))/((A1B2)-(A2B1));
y=((A1C2)-(A2C1))/((A1B2)-(A2B1));

代碼

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e5+5; const ll mod=998244353; double eqs=1e-6; struct Point{double x,y;Point(){}Point(double xx,double yy){x=xx;y=yy;} }e[maxn]; Point operator+(Point a,Point b){ //向量加return Point(a.x+b.x,a.y+b.y); } Point operator-(Point a,Point b){ //向量減return Point(a.x-b.x,a.y-b.y); } double sqr(double x){return x*x; } double dis(Point a,Point b){ //求ab的長度return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); } Point Circum(Point a,Point b,Point c){ //三角形外心double x1=a.x,y1=a.y;double x2=b.x,y2=b.y;double x3=c.x,y3=c.y;double a1=2*(x2-x1);double b1=2*(y2-y1);double c1=x2*x2+y2*y2-x1*x1-y1*y1;// double a2=2*(x3-x2);double b2=2*(y3-y2);double c2=x3*x3+y3*y3-x2*x2-y2*y2;double x=(c1*b2-c2*b1)/(a1*b2-a2*b1);double y=(a1*c2-a2*c1)/(a1*b2-a2*b1);return Point(x,y); } map<pair<double,double>,int> m; int main() {int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%lf %lf",&e[i].x,&e[i].y);}Point o=Point(0,0);int ans=0;for(int i=1;i<=n;i++){m.clear();for(int j=1;j<=n;j++){if(e[i].x*e[j].y-e[j].x*e[i].y<=eqs) continue;//如果平行 Point oo=Circum(o,e[i],e[j]);ans=max(++m[make_pair(oo.x,oo.y)],ans);}}printf("%d\n",ans+1);return 0; }

總結

以上是生活随笔為你收集整理的Boundary(2020多校第二场B)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。