第九届河南省ACM省赛 D 导弹发射

来源:互联网 发布:编程求出100以内的质数 编辑:程序博客网 时间:2024/04/28 10:28

D 导弹发射


Description

Alpha 机构研发出一种新型智能导弹,它能够在雷达检测到的区域内,选择一条前进的路径,
击破路径上所有的目标物。
雷达位于(0,0)处,它能够检测到两条射线之间的区域(不妨设在第一象限)。
导弹一开始置放在(0,0)处,它可以在雷达能检测到的区域内先选择一个目标物击破,然后
再继续前进,选择另一个目标物击破。注意,导弹不能沿着这两条射线前进,当然也不能停在原
地。
可以假设,导弹一旦发射,其能量无比大,前进的路径无限长。
已知雷达能够检测到区域,其射线 1:ax-by=0 和射线 2:cx-dy=0。Alpha 机构的总指挥希望
在发现目标群的第一时刻,计算出一条可以击破最多目标物的路径。

Input

第一行: T 表示以下有 T 组测试数据(1≤T ≤8)
对每组测试数据:
第 1 行: n 表示目标物的个数
第 2 行: a b c d 代表两条射线的斜率分别是 a/b 和 c/d。
接下来有 n 行,每行 2 个正整数 xi yi 即第 i 个目标物的坐标。
(1) n<=10^5 0<=a, b, c, d<=10^5 a 和 b 不会同时为 0,c 和 d 不会同时为 0;
(2) 0<= xi , yi <=10^6 i=1,…..,n

Output

每组测试数据,输出占一行,即导弹能击破的最多目标数。

Sample Input

1
15
1 3 2 1
3 1
6 2
4 2
2 5
4 5
6 6
3 4
1 6
2 1
7 4
9 3
5 3
1 3
15 5
12 4

Sample Output

4


解题思路:
     首先,我们只需要考虑在曲线之内的点。然后思考,如何判断导弹是前进的?(这个问题在比赛的时候一直困扰我)我们将两条射线看成x轴和y轴进行坐标变换,有了新的坐标后,很容易可以判断前进的情况(x递增,y递增)。变换之后用nlogn的LIS求解即可。这里要注意一个问题,当x轴不变,y轴增大时,LIS有可能将其统计在内。我们在排序时设置,当x相等时y从大到小排序,可以解决上述问题。
     这题的题面其实表达的不是很清楚,比如是否有多个目标在同一位置,两条射线的相对位置是否固定。。。然而题目在不考虑这些因素的情况下都能A。。。



代码:

#include <iostream>#include<bits/stdc++.h>using namespace std;const int N=110000;struct node{    double x,y;}a[N],b[N];bool cmp(node a,node b)//先按x从小到大排序,如果x相等按y从大到小排序,这样排除了沿y轴前进的情况{    if(a.x==b.x)    return a.y>b.y;    return a.x<b.x;}int Search(int num,int low,int high){    int mid;    while(low<=high)    {        mid=(low+high)/2;        if(a[num].y>b[mid].y) low=mid+1;        else    high=mid-1;    }    return low;}int dp(int n)//LIS nlogn模板{    int i,len,pos;    b[1].x=a[1].x;    b[1].y=a[1].y;    len=1;    for(int i=2;i<=n;i++)    {        //两个点在同一位置的情况,数据中没有        //if(a[i].y>b[len].y&&a[i].x>b[len].x||a[i].x==b[len].x&&a[i].y==b[len].y)        if(a[i].y>b[len].y&&a[i].x>b[len].x)        {            len=len+1;            b[len].y=a[i].y;            b[len].x=a[i].x;        }        else        {            pos=Search(i,1,len);            b[pos].y=a[i].y;            b[pos].x=a[i].x;        }    }    return len;}int main(){    int T,n;    double a1,b1,c1,d1;    cin>>T;    while(T--)    {        cin>>n;        cin>>a1>>b1>>c1>>d1;        //保证c1/d1射线在a1/b1上面,数据中不存在相反情况        /*if(b1==0||c1==0||(b1!=0&&d1!=0&&c1/d1<a1/b1))        {            swap(a1,c1);            swap(b1,d1);        }*/        int cnt=0;        for(int i=1;i<=n;i++)        {            double x,y;            scanf("%lf%lf",&x,&y);            //如果点在两个射线之内            if(y*d1<x*c1&&x*a1<y*b1)            {                cnt++;                //坐标变换                a[cnt].x=(x-y*d1/c1)*c1/sqrt(c1*c1+d1*d1);                a[cnt].y=(y-x*a1/b1)*b1/sqrt(a1*a1+b1*b1);            }        }        sort(a+1,a+cnt+1,cmp);        cout<<dp(cnt)<<endl;    }}

0 0
原创粉丝点击