1071: [SCOI2007]组队
Time Limit: 3 Sec Memory Limit: 128 MB
Description
NBA每年都有球员选秀环节。通常用速度和身高两项数据来衡量一个篮球运动员的基本素质。假如一支球队里
速度最慢的球员速度为minV,身高最矮的球员高度为minH,那么这支球队的所有队员都应该满足: A * ( height
– minH ) + B * ( speed – minV ) <= C 其中A和B,C为给定的经验值。这个式子很容易理解,如果一个球队的
球员速度和身高差距太大,会造成配合的不协调。 请问作为球队管理层的你,在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
数据范围: N <= 5000 ,height和speed不大于10000。A、B、C在长整型以内。
思路:
一看,这不是n^3吗?再仔细想想,还是n^3呀!
绝望。。n^2log好像也过不了诶(还是有大佬卡过),n^2是正解??枚举minH,minS不就n^2了吗?难道是指针扫一遍,听着像那么回事。额,但是写不来。。%大佬
弄两个数组保存信息,同时处理每个运动员val=A * h+B * s,sh数组按h排序,sv数组按val排序。
外层在sh中枚举i(minS),内层在sh数组里升序枚举j(minH),拿l,r两个指针在sh和sv里面扫。用r扫sv数组添加球员,用l扫sh数组删减球员。
移项可知sv[r].val<=A * minH+B * minS+C时sv[r]才可能被选中
这时sv[r]还要保证s>minS,同时我们不能让v过大导致h比之前的minH小(本来就是非法状态,也保证不到l指针处理过的区间里去),所以把h从式子里去掉再移项得s<=minS+C/B。
然后用l扫sh数组删除不合法的球员,如果一个球员的h比minH小并且满足上边s的判定条件,那么就把它删掉>
为什么不在扫r指针时用h>=minH判h是否合法呢?因为在内层枚举时minH在增加,可能它对于当前的minH合法了,但是之后又不合法了。
还有一些细节和原因请参照代码注释。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int N = 5010;
int n,ans;
LL A, B, C;
struct ER{
int h, s;
LL val;
}sh[N], sv[N];
inline bool cmph(ER aa, ER bb){
return aa.h < bb.h;
}
inline bool cmpv(ER aa, ER bb){
return aa.val < bb.val;
}
int main(){
cin >> n >> A >> B >> C;
for(int i=1; i<=n; i++){
scanf("%d%d", &sh[i].h, &sh[i].s);
sh[i].val = A * sh[i].h + B * sh[i].s;
sv[i] = sh[i];
}
sort(sh+1, sh+n+1, cmph);
sort(sv+1, sv+n+1, cmpv);
int l, r, cnt;
for(int i=1; i<=n; i++){//枚举i为speed最小的球员
l = r = 0; cnt = 0;
LL mx = sh[i].s + C / B;//超过mx,h就一定小于 sh[j].h了
for(int j=1; j<=n; j++){//枚举j为height最小的球员
while(r<n && sv[r+1].val<=A*sh[j].h+B*sh[i].s+C){//满足条件A*(height-minH)+B*(speed-minV)<=C
r++;//A*sh[j].h+B*sh[i].s+C是递增的,所以对于每一个i,r都是单调的
if(sv[r].s>=sh[i].s && sv[r].s<=mx) cnt++;
//因为sv[r+1].val>A*sh[j-1].h+B*sh[i].s+C(终止while的条件)
//所以只要我们保证 sv[r+1].s<=mx 那么 sv[r+1].h 就一定大于sh[j-1].h
//这样的话这个球员才会在一会删除的时候考虑到
}//统计了不考虑h的合法球员。
while(l<n && sh[l+1].h<sh[j].h){
l++;//sh[j].h是递增的,所以对于每一个i,l都是单调的
if(sh[l].s>=sh[i].s && sh[l].s<=mx/* && sh[l].val<=A*sh[j].h+B*sh[i].s+C*/) cnt--;
}//sh[l].s<=mx && sh[l].h<sh[j].h 所以A*sh[l].h+B*sh[i].s < A*sh[j].h+B*sh[i].s+C
//一定满足sh[l].val<=A*sh[j].h+B*sh[i].s+C,也就是说一定是加入过的(不重不漏)
ans = max(ans, cnt);
}
}
printf("%d\n", ans);
return 0;
}