CF645G Armistice Area Apportionment 题解
题意 给定平面上 n 个点和 a。设 P(a,0),Q(-a,0)。要求找出一条直线 l 过至少两个给定点,最小化 max{ PX-QX},Xin l。 nle10^5,ale 10^4。 题解 计算…
题意
给定平面上 个点和 。设 。要求找出一条直线 过至少两个给定点,最小化 。
。
题解
计算
首先我们来看看,假如确定某两个点 这个东西是怎么算的,根据将军饮马的知识

第一种情况 在 同侧,观察 可得,,所以可得,。

第二种情况 在 异侧,故做 关于 的对称点 ,观察 可得,,所以可得,。
解题
由于答案最大就是 ,所以不需要特别考虑第二种情况。现在只计算第一种情况,最大最小值直接套路用二分答案,若当前二分 这个答案,考虑怎么 check。这样二分的几何意义就是某一个 点在以 为圆心,半径为 圆内,记这个圆为圆 。进而考虑 怎么转化,就是以 为圆心 为半径的圆和以 为圆心 为半径的圆的其中一个交点,分别记为圆 ,那么这样转化的好处是把 贡献拆分开了,两个圆是独立的。现在记圆 在圆 内的弧分别为 ,那么两个圆的交点在 可以转化为 和 是有交,但是可能圆 是包含关系,所以 和 不能是包含关系。这个很好判和括号序差不多,求出圆 和圆 的交点和圆心到交点的向量幅角,用栈判断就可以了。这个过程不好理解可以看我画的 GeoGebra。
#include<bits/stdc++.h>
// #define ONLINE_JUDGE
#define INPUT_DATA_TYPE int
#define OUTPUT_DATA_TYPE int
inline __attribute((always_inline)) INPUT_DATA_TYPE read(){register INPUT_DATA_TYPE x=0;register char f=0,c=getchar();while(c<'0'||'9'<c)f=(c=='-'),c=getchar();while('0'<=c&&c<='9')x=(x<<3)+(x<<1)+(c&15),c=getchar();return f?-x:x;}void print(OUTPUT_DATA_TYPE x){if(x<0)x=-x,putchar('-');if(x>9)print(x/10);putchar(x%10^48);return;}
struct point{
double x,y;
point operator + (const point &o) const {return {x+o.x,y+o.y};}
point operator - (const point &o) const {return {x-o.x,y-o.y};}
point operator * (const double &o) const {return {x*o,y*o};}
};
struct circle{
point o;
double r;
}a[100010];
double moo(point a){return std::sqrt(a.x*a.x+a.y*a.y);}
double dist(point a,point b){return moo(a-b);}
point unit(point a){return a*(1.0/moo(a));}
double polarAngle(point a){return atan2(a.y,a.x);}
auto intersect(circle a,circle b){
double d=dist(a.o,b.o);
double x=(a.r*a.r+d*d-b.r*b.r)/(d*2);
double z=std::sqrt(a.r*a.r-x*x);
point u=unit(b.o-a.o);
point mid=a.o+u*x;
std::swap(u.x,u.y),u.x*=-1;
return std::make_pair(mid+u*z,mid-u*z);
}
point p,q;
int n;
bool check(double mid){
register int i;
register double d;
std::vector<std::pair<double,int>> vec;
std::stack<int> S;
circle o={p,mid};
for(i=0;i<n;++i){
d=dist(o.o,a[i].o);
if(o.r+a[i].r>d&&fabs(o.r-a[i].r)<d){
auto tmp=intersect(o,a[i]);
vec.push_back({polarAngle(tmp.first-o.o),i});
vec.push_back({polarAngle(tmp.second-o.o),i});
}
}
std::sort(vec.begin(),vec.end());
for(auto val:vec)
if(S.empty()||S.top()!=val.second) S.push(val.second);
else S.pop();
return !S.empty();
}
int main(){
#ifndef ONLINE_JUDGE
freopen("name.in", "r", stdin);
freopen("name.out", "w", stdout);
#endif
register int i;
register double l,r,mid;
n=read();
int aa=read();
p.x=aa,q.x=-aa;
for(i=0;i<n;++i) a[i].o.x=read(),a[i].o.y=read(),a[i].r=dist(a[i].o,q);
l=0,r=dist(p,q);
for(i=0;i<50;++i){
mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.10lf",l);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}谢谢你,读到这里。
本文同步自洛谷专栏,保留原始正文与发布时间。在洛谷查看原文 ↗