蛤省前几年的省选题有点水啊.
对于每个点,可以用r和y算出能覆盖到它的望远镜的的坐标的左右范围,算出这个后,我们发现,问题转化成了,一条直线上有n个线段,如何用最少的点放在坐标轴上使所有线段上至少有一个点.
对于这个问题,首先观察到包含别的线段的线段不用考虑,先去掉.
去完后,发现整个轴成了线段不断交替的过程,然后贪心即可.
#include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<string> #include<map> #include<cstdlib> #include<cmath> #include<cstdio> #include<ctime> #include<queue> using namespace std; #define LL long long #define FILE "dealing" #define eps 1e-10 #define db double #define pii pair<int,int> #define up(i,j,n) for(int i=j;i<=n;i++) int read(){ int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return x*f; } const int maxn=500,mod=1000000007,inf=100000007; bool cmin(int& a,int b){return a>b?a=b,true:false;} bool cmax(int& a,int b){return a<b?a=b,true:false;} int n; double r; struct node{ double x,y,lef,rig; }e[maxn]; bool cmp(node a,node b){return a.lef<b.lef;} int main(){ //freopen(FILE".in","r",stdin); //freopen(FILE".out","w",stdout); n=read(),r=read(); up(i,1,n)e[i].x=read(),e[i].y=read(),e[i].rig=e[i].x+sqrt(r*r-e[i].y*e[i].y),e[i].lef=e[i].x-sqrt(r*r-e[i].y*e[i].y); sort(e+1,e+n+1,cmp); //up(i,1,n)printf("%.2lf %.2lf %.2lf %.2lf ",e[i].x,e[i].y,e[i].lef,e[i].rig); int head=0,tail=0; node q[maxn]; up(i,1,n){ while(head<tail&&q[tail].rig>e[i].rig)tail--; q[++tail]=e[i]; } n=tail-head+1; up(i,1,n)e[i]=q[i]; //cout<<endl; //up(i,1,n)printf("%.2lf %.2lf %.2lf %.2lf ",e[i].x,e[i].y,e[i].lef,e[i].rig); int top=0; int b[maxn];b[0]=-inf; up(i,1,n)if(b[top]<e[i].lef)b[++top]=e[i].rig; cout<<top<<endl; return 0; }