计算几何题,要么全场AK,要么全场骗分,那是因为当几何中各种精巧的转化与OI多变的解题方法融合在一起时,答案总是和乱搞很难区分。
这道题也算乱搞吧,这种题一般要枚举一个点,再继续分析,我们可以发现,做一个点关于圆的两条切线,在两条切线中间的点是不能选的。
然后是我的乱搞:
两条切线会将图分为3部分,一是枚举的点,二是切线左方的点,三是切线右方的点,
然后我认为左方的点和左方的点不会排斥,那么左边和右边成一个二分图,求一个最大独立集。
然而我错了。
正解:
两条切点之间的圆弧,可以发现,若两个点可以同时选,则两个圆弧的关系既不能是包含也不能是独立,得相交
所以把圆弧求出来,转化为最多选几条弧,每两条弧都相交且不包含。。。。。。
然后按左端点排序,求最长上升子序列:
ACcode:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define maxn 4005
#define PI 3.1415926535897932384626433832795
#define inf 0x3f3f3f3f
using namespace std;
int n;
double R;
double l[maxn],r[maxn];
double sqr(double a){
return a*a;
}
struct Point{
double x,y;
Point(){}
Point(double a,double b){x=a,y=b;}
bool operator <(const Point nxt)const{
return x<nxt.x;
}
double operator *(const Point nxt)const{
return sqrt(sqr(y-nxt.y)+sqr(x-nxt.x));
}
}P[maxn],O;
struct node{
double l,r;
bool operator <(const node nxt)const{
return l<nxt.l;
}
}s[maxn];
double Q[maxn];
int tp;
int main(){
freopen("clique.in","r",stdin);
freopen("clique.out","w",stdout);
double sita,alph;
scanf("%d%lf",&n,&R);
for(int i=1;i<=n;i++){
scanf("%lf%lf",&P[i].x,&P[i].y);
if(P[i]*O<R){
n--,i--;
continue;
}
alph=atan2((P[i].y),(P[i].x));
sita=acos((R)/(P[i]*O));
s[i].l=alph-sita;
s[i].r=alph+sita;
if(s[i].r>PI) s[i].r-=2*PI,swap(s[i].l,s[i].r);
if(s[i].l<-PI) s[i].l+=2*PI,swap(s[i].l,s[i].r);
}
sort(s+1,s+1+n);
int ans=0;
for(int i=1;i<=n;++i)
{
Q[tp=0]=s[i].r;tp++;
for(int j=i+1;j<=n && s[j].l<Q[0]; j++)
if(s[j].r>Q[tp-1]) Q[tp++]=s[j].r;
else
if(s[j].r>Q[0])
*lower_bound(Q,Q+tp,s[j].r)=s[j].r;
ans=max(ans,tp);
}
printf("%d",ans);
}