一.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;
}
(1)题目大意
(2)解题思路
考虑这三个柱子构成一个三角形,那么这个多边形得顶点一定挂在三角形得外接圆上。
考虑这个外接圆得半径,又
,所以
。考虑圆心角度数皆为正多边形得中心角度数倍数,因此可以求三个圆心角得最大公约数,(由于题目中给定多边形数不超过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;
}