洛谷传送门
BZOJ传送门
题目描述
NBA每年都有球员选秀环节。通常用速度和身高两项数据来衡量一个篮球运动员的基本素质。假如一支球队里速度最慢的球员速度为 m i n V minV minV,身高最矮的球员高度为 m i n H minH minH,那么这支球队的所有队员都应该满足: A × ( h e i g h t – m i n H ) + B × ( s p e e d – m i n V ) ≤ C A × ( height – minH ) + B × ( speed – minV ) \le C A×(height–minH)+B×(speed–minV)≤C 其中 A A A和 B B B, C C C为给定的经验值。这个式子很容易理解,如果一个球队的球员速度和身高差距太大,会造成配合的不协调。
请问作为球队管理层的你,在 N N N名选秀球员中,最多能有多少名符合条件的候选球员。
输入输出格式
输入格式:
第一行四个数 N N N、 A A A、 B B B、 C C C 下接 N N N行每行两个数描述一个球员的 h e i g h t height height和 s p e e d speed speed
输出格式:
最多候选球员数目。
输入输出样例
输入样例#1:
4 1 2 10
5 1
3 2
2 3
2 1
输出样例#1:
4
说明
数据范围:$ N \le 5000$ , h e i g h t height height和 s p e e d speed speed不大于 10000 10000 10000。 A A A、 B B B、 C C C在长整型以内。
解题分析
好妙妙的一道题啊…
首先转化式子: 为了方便将
h
e
i
g
h
t
height
height记为
h
h
h,
s
p
e
e
d
speed
speed记为
v
v
v。 那么有:
A
h
+
B
v
≤
A
m
i
n
H
+
B
m
i
n
V
+
C
Ah+Bv\le AminH+BminV+C
Ah+Bv≤AminH+BminV+C
那么我们固定一维
m
i
n
V
minV
minV, 然后从小到大枚举
m
i
n
H
minH
minH, 发现式子右边单增, 所以把所有球员按
A
h
+
B
v
Ah+Bv
Ah+Bv排序, 一个一个加入队列中。 注意合乎条件的球员一定满足
s
∈
[
m
i
n
V
,
m
i
n
V
+
C
B
]
s\in[minV, minV+\frac{C}{B}]
s∈[minV,minV+BC], 否则左边一定比右边大。 在这个过程中统计合法的球员个数。
但这样加进来的球员不一定满足 h ≥ H h\ge H h≥H的限制, 所以我们把所有球员按 h h h从小到大排序, 然后逐个pop, 如果遇到 v v v符合条件的球员, 那么这个球员一定被统计过了(因为 A h + B v Ah+Bv Ah+Bv一定 ≤ \le ≤当前不等式右边的值), 直接减去贡献即可。
总复杂度是 O ( N 2 ) O(N^2) O(N2)。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define ll long long
#define W while
#define gc getchar()
#define MX 5050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int n, ans;
ll A, B, C, down, up;
struct INFO {ll h, v, s;} dat[2][MX];
IN bool cmph(const INFO &x, const INFO &y) {return x.h < y.h;}
IN bool cmps(const INFO &x, const INFO &y) {return x.s < y.s;}
IN bool calc(R int id, R int pos) {return dat[id][pos].v >= down && dat[id][pos].v <= up;}
int main(void)
{
int h1, h2, cnt;
in(n), in(A), in(B), in(C);
for (R int i = 1; i <= n; ++i)
{
in(dat[0][i].h), in(dat[0][i].v);
dat[0][i].s = A * dat[0][i].h + B * dat[0][i].v;
dat[1][i] = dat[0][i];
}
std::sort(dat[0] + 1, dat[0] + 1 + n, cmph);
std::sort(dat[1] + 1, dat[1] + 1 + n, cmps);
for (R int i = 1; i <= n; ++i)
{
h1 = h2 = cnt = 0;
down = dat[0][i].v, up = dat[0][i].v + C / B;
for (R int j = 1; j <= n; ++j)
{
ll S = C + A * dat[0][j].h + B * down;
W (h1 < n && dat[1][h1 + 1].s <= S) ++h1, cnt += calc(1, h1);
W (h2 < n && dat[0][h2 + 1].h < dat[0][j].h) ++h2, cnt -= calc(0, h2);
ans = std::max(ans, cnt);
}
}
printf("%d\n", ans);
}