题解 P8133【[ICPC2020 WF] Ley Lines】
[ICPC2020 WF] Ley Lines
抢一下第一篇题解,本题解采用弧度制,其中
首先有一个引理,就是一定存在一个最优解使得有一个点在线的边界上。证明很简单,如果不在边界上的话,我们可以平移两条线,直到其中一条碰到某个点为止。不难发现在这个过程中答案是不会变的。
枚举那个在边界上的点。然后以这个点为原点,模拟粗线转绕原点转一圈的过程,求出在这个过程中每个点分别在哪个角度区间会被覆盖。
遍历其余的点,设当前点的极角为
若
若
可以画图理解,下图以区间
把所有区间处理出来后,按照极角升序做一遍扫描线即可,时间复杂度
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef long double ld;
using namespace std;
const int N=3010,M=30010,INF=0x3f3f3f3f;
const ld eps=1e-6,pi=acos(-1),inf=1e9;
int n,m,ans,res;
vector<pair<ld,int> > v;
struct node{
ll x,y;
node(ll xx=0,ll yy=0){x=xx,y=yy;}
void in(){scanf("%lld%lld",&x,&y);}
void out(){printf("%lld %lld\n",x,y);}
}p[N];
node operator +(node a,node b){return node(a.x+b.x,a.y+b.y);}
node operator -(node a,node b){return node(a.x-b.x,a.y-b.y);}
ll operator *(node a,node b){return a.x*b.x+a.y*b.y;}
ll operator ^(node a,node b){return a.x*b.y-a.y*b.x;}
node operator *(ll x,node b){return node(x*b.x,x*b.y);}
ld sqr(ld x){return x*x;}
ld dis(node a,node b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
ld get(ld x){return x<0?2*pi+x:x;}
ld taninv(ld y,ld x){return get(atan2(y,x));}
void add(ld l,ld r){
v.pb(mp(l,1)),v.pb(mp(r,-1));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)p[i].in();
for(int i=1;i<=n;i++){
v.clear();res=1;
for(int j=1;j<=n;j++){
if(i==j)continue;
node b=p[j]-p[i];
ld t=taninv((ld)b.y,(ld)b.x),r=dis(p[i],p[j]),s=asin((ld)m/r);
if(r<(ld)m)add(t,t+pi);
else add(t,t+s),add(t-s+pi,t+pi);
}
sort(v.begin(),v.end());
for(pair<ld,int> t:v)
res+=t.se,ans=max(ans,res);
}
printf("%d\n",ans);
return 0;
}