[Luogu P4165] [BZOJ 1071] [SCOI2007]组队

洛谷传送门
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×(heightminH)+B×(speedminV)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+BvAminH+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 hH的限制, 所以我们把所有球员按 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);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值