题目链接:http://nyoj.top/problem/1275
- 内存限制:64MB 时间限制:1000ms
题目描述
Alpha 机构研发出一种新型智能导弹,它能够在雷达检测到的区域内,选择一条前进的路径, 击破路径上所有的目标物。 雷达位于(0,0)处,它能够检测到两条射线之间的区域(不妨设在第一象限)。 导弹一开始置放在(0,0)处,它可以在雷达能检测到的区域内先选择一个目标物击破,然后 再继续前进,选择另一个目标物击破。注意,导弹不能沿着这两条射线前进,当然也不能停在原 地。 可以假设,导弹一旦发射,其能量无比大,前进的路径无限长。 已知雷达能够检测到区域,其射线 1:ax-by=0 和射线 2:cx-dy=0。Alpha 机构的总指挥希望 在发现目标群的第一时刻,计算出一条可以击破最多目标物的路径。
输入描述
第一行: 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
输出描述
每组测试数据,输出占一行,即导弹能击破的最多目标数。
样例输入
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
样例输出
4
解题思路
寻找射线内不与两条射线平行的LIS,首先输入的时候计算斜率,判断每个点是否在射线内,然后就是重建坐标系,方便判断递增,我采用的方法是,将横坐标减去该点在上射线投影点的x值,纵坐标减去该点在下射线投影点的y值,将坐标转换完毕后就是平面上的LIS问题了,不过要注意的是只能使用二分的方法写,不然会超时。
#include <bits/stdc++.h>
using namespace std;
struct edge {
double x, y;
}e[100005], dp[100005];
bool cmp(edge A, edge B) {
if (A.x != B.x)
return A.x < B.x;
return A.y > B.y;
}
int Search(int k, int l, int r) {
int mid;
while (l <= r) {
mid = (l + r) >> 1;
if (dp[mid].y < e[k].y)
l = mid + 1;
else r = mid - 1;
}
return l;
}
int main() {
int t, l, k, n;
double a, b, c, d, x, y, k1, k2, k3;
scanf("%d", &t);
while (t--) {
k = l = 0;
scanf("%d", &n);
scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
k2 = a / b;
k1 = c / d;
if (k1 < k2)
swap(k1, k2);
for (int i = 0; i < n; i++) {
scanf("%lf%lf", &x, &y);
k3 = y / x;
if (k3 > k2 && k3 < k1) {
e[k].x = x - y / k1;
e[k++].y = y - k2 * x;
}
}
sort(e, e + k, cmp);
dp[l++] = e[0];
for (int i = 1; i < k; i++) {
if (e[i].x > dp[l - 1].x && e[i].y > dp[l - 1].y)
dp[l++] = e[i];
else {
int mit = Search(i, 0, l);
dp[mit] = e[i];
}
}
printf("%d\n", l);
}
return 0;
}