[BZOJ]1071 组队(SCOI2007) -- 尺取法

Description

NBA每年都有球员选秀环节。通常用速度和身高两项数据来衡量一个篮球运动员的基本素质。假如一支球队里速度最慢的球员速度为minV,身高最矮的球员高度为minH,那么这支球队的所有队员都应该满足: A * ( height – minH ) + B * ( speed – minV ) <= C 其中A和B,C为给定的经验值。这个式子很容易理解,如果一个球队的球员速度和身高差距太大,会造成配7合的不协调。 请问作为球队管理层的你,在N名选秀球员中,最多能有多少名符合条件的候选球员。

Input

第一行四个数N、A、B、C 下接N行每行两个数描述一个球员的height和speed。

Output

最多候选球员数目。

Sample Input
  4 1 2 10
  5 1
  3 2
  2 3
  2 1

Sample Output
  4

HINT

1 <= N <= 5000,0<= height,speed <= 10000,A、B、C在长整型以内且为正数。

Solution

  • 可以想到n^3的暴力枚举方法
  • 但是时间会爆,想想优化
  • 天外飞来两个推导式:hi <= C/A + H && Ahi + Bvi <= AH+B*V+C
  • 枚举H用这两个式子判断vi的合法性

#include <bits/stdc++.h>
#define il inline
#define re register

using namespace std;
typedef long long ll;
const int maxn = 5010;
int n, a, b, c;
int ans;
struct node{
	int h, v;
	int w;
}eh[maxn], ew[maxn];
il bool cmph(node x, node y) {
	return x.h < y.h; 
}
il bool cmpw(node x, node y) {
	return x.w < y.w;
}
int main() {
	ans = 0;
	scanf("%d%d%d%d", &n, &a, &b, &c);
	for(re int i = 1; i <= n; ++i) {
		scanf("%d%d", &eh[i].h, &eh[i].v);
		eh[i].w = a*eh[i].h + b*eh[i].v;
		ew[i] = eh[i];
	}
	sort(eh+1, eh+n+1, cmph);
	sort(ew+1, ew+n+1, cmpw);
	for(re int i = 1; i <= n; ++i) {
		//枚举v
		int minv = eh[i].v;
		int l = 1, r = 1, cnt = 0;
		for(re int j = 1; j <= n; ++j) {
			//因为h有序,所以从左到右移就行
			int minh = eh[j].h;
			while(r <= n && ew[r].w <= a*minh + b*minv + c) {
				if(ew[r].v >= minv && ew[r].v <= c/b + minv)//合法(要加) 
					cnt++;
				r++;
			}
			while(l <= n  && eh[l].h < minh) {//不合法 
				if(eh[l].v >= minv && eh[l].v <= c/b + minv)//合法(已加) 
					cnt--;
				l++;
			}
			ans = max(ans, cnt);
		}
	}
	printf("%d\n", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值