计算几何

一.Problem - A - Codeforces(hash斜率+离线处理)

        (1)题目大意

         (2)解题思路

                这个题看了一下n发现可以n^2logn枚举,因此我们考虑先把查询离线,枚举查询的点是直角顶点和非直角顶点的答案,然后把他加入到查询答案就行了,注意这里斜率不能直接除,我们考虑hash把斜率处理了。

        (3)代码实现

#include "bits/stdc++.h"
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define ll long long
#define ull unsigned long long
#define db double
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e3 + 10;
struct Point{ll x,y;}Q[N],P[N];
//把斜率转换成hash值
ull getHash(Point v)
{
    ull A = 133,B = 13331,C = 13333331;
    return A * v.x + B * v.y + C;
}
//计算斜率
Point getSlope(Point v1,Point v2)
{
    ll dx = v1.x - v2.x,dy = v1.y - v2.y;
    if(dx == 0) return {0,1};
    if(dy == 0) return {1,0};
    ll d = __gcd(dx,dy);
    return {dx / d,dy / d};
}
unordered_map <ull,int> mp;
int ans[N];
void solve()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i = 1;i <= n;i++) scanf("%lld%lld",&P[i].x,&P[i].y);
    for(int i = 1;i <= q;i++) scanf("%lld%lld",&Q[i].x,&Q[i].y);
    //计算以查询点为直角定点的答案
    for(int i = 1;i <= q;i++) {
        mp.clear();
        for(int j = 1;j <= n;j++) {
            Point tmp = getSlope(Q[i],P[j]);
            mp[getHash(tmp)] ++;
        }
        for(int j = 1;j <= n;j++) {
            Point tmp = getSlope(Q[i],P[j]);
            if(tmp.x == 0 && tmp.y == 1 && mp.count(getHash({1,0}))) ans[i] += mp[getHash({1,0})];
            else if(tmp.x == 1 && tmp.y == 0 && mp.count(getHash({0,1}))) ans[i] += mp[getHash({0,1})];
            else ans[i] += mp[getHash({-tmp.y,tmp.x})] + mp[getHash({tmp.y,-tmp.x})];
        }
        //减去重复部分
        ans[i] /= 2;
    }
    //计算查询点为非直角定点的答案
    for(int i = 1;i <= n;i++) {
        mp.clear();
        for(int j = 1;j <= n;j++) {
            if(i == j) continue;
            Point tmp = getSlope(P[i],P[j]);
            mp[getHash(tmp)] ++;
        }
        for(int j = 1;j <= q;j++) {
            Point tmp = getSlope(P[i],Q[j]);
            if(tmp.x == 0 && tmp.y == 1 && mp.count(getHash({1,0}))) ans[j] += (mp[getHash({1,0})]);
            else if(tmp.x == 1 && tmp.y == 0 && mp.count(getHash({0,1}))) ans[j] += (mp[getHash({0,1})]);
            else ans[j] += (mp[getHash({-tmp.y,tmp.x})] + mp[getHash({tmp.y,-tmp.x})]);
        }
    }
    for(int i = 1;i <= q;i++) cout << ans[i] << endl;
}
int main()
{
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

二.Problem - 1C - Codeforces

        (1)题目大意

        (2)解题思路

                考虑这三个柱子构成一个三角形,那么这个多边形得顶点一定挂在三角形得外接圆上。

考虑这个外接圆得半径R=\frac{c}{2sinC},又S_{abc} = \frac{absinC}{2},所以R=\frac{abc}{4S_{abc}}。考虑圆心角度数皆为正多边形得中心角度数倍数,因此可以求三个圆心角得最大公约数,(由于题目中给定多边形数不超过100,因此求gcd时候eps可以取1e-2),求完最大公约数就可以得到每个中心角度数,然后可以得知是多少正多边形,可以用多个三角形得面积加起来即为这个正多边形面积。(实现得时候注意会有精度问题,记得调整精度)

        (3)代码实现

#include <bits/stdc++.h>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
const long double pi = acos(-1);
const long double eps = 1e-2;
const long double EEps = 1e-14;
long double x[N],y[N],d[N];
long double A[N];
long double get(int i,int j)
{
    long double dx = (x[i] - x[j]);
    long double dy = (y[i] - y[j]);
    return sqrtl(dx * dx + dy * dy);
}
long double Ang(long double d,long double r)
{
    long double v = ((r * r * 2 - d * d) / (2 * r * r));
    while(v < -1.0) v += EEps;
    while(v > 1.0) v -= EEps;
    return acos(v);
}
long double Mod(long double a,long double b)
{
    return a - (ll)(a / b) * b;
}
long double Gcd(long double a,long double b)
{
    if(fabs(b) < eps) return a;
    return Gcd(b,Mod(a,b));
}
void solve()
{
    rep(i,1,3) cin >> x[i] >> y[i];
    d[1] = get(1,2);
    d[2] = get(1,3);
    d[3] = get(2,3);
    long double P = (d[1] + d[2] + d[3]) / 2;
    long double S = sqrtl(P * (P - d[1]) * (P - d[2]) * (P - d[3]));
    long double R = d[1] * d[2] * d[3] / 4 / S;
    A[1] = Ang(d[1],R);
    A[2] = Ang(d[2],R);
    A[3] = 2 * pi - A[1] - A[2];
    cout << fixed << setprecision(8);
    long double G = Gcd(A[1],Gcd(A[2],A[3]));
    long double Area = pi * R * R * sin(G) / G;
    cout << Area << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值