【SCOI2007】【BZOJ1071】组队

来源:互联网 发布:pp2000软件 编辑:程序博客网 时间:2024/05/16 07:33

原题链接:原题地址
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在长整型以内。
朴素想法:直接枚举minh和minv再统计符合要求个数,时间复杂度为O(n^3),无法承受。可以换个思路(以下用a和b代替身高和速度):
由题目的不等式A * ( height – minH ) + B * ( speed – minV ) <= C ,移项后为A*height+B*speed<=C+A*minH+B*minV。那么可以以定义c[i]=A*a[i]+B*b[i],枚举到一个mina和minb时,设lim=A*mina+B*minb,则只需统计满足c[i]<=lim的个数。我们以c[i]的值对运动员排序,先枚举mina,再从小到大枚举minb,计算好lim,用一个指针p指向当前扫到的c[i],并且一直右移指针直到c[i]>lim。此时换下一个minb因为b从小到大枚举,显然lim的值不会变小,则指针p也不会回溯。但注意随着minb的值增大,之前计算过的人中可能会有人的b值会小于minb。解决方法很简单,用cnt表示当前mina下找到的队员个数,在计算完当前mina和minb的cnt并且更新了答案之后,如果这个minb对应的队员的c值大于lim,那么cnt–即可。

#include<iostream>#include<cstdio>#include<algorithm>#define maxn 5010using namespace std;struct man{    int a,b,c;}da[maxn],bb[maxn];bool cmp1(man a,man b){    return a.b<b.b;}bool cmp2(man a,man b){    return a.c<b.c;}int main(){    freopen("10396.in","r",stdin);    int n,a0,b0,c0;    scanf("%d%d%d%d",&n,&a0,&b0,&c0);    for(int i=1;i<=n;i++){        scanf("%d%d",&da[i].a,&da[i].b);        da[i].c=a0*da[i].a+b0*da[i].b;        bb[i]=da[i];    }    sort(da+1,da+n+1,cmp2);    sort(bb+1,bb+n+1,cmp1);    int ans=0;    for(int i=1;i<=n;i++){        int p=1,cnt=0;        for(int j=1;j<=n;j++)if(da[i].a<=bb[j].a&&bb[j].b<=da[i].b){            int lim=a0*da[i].a+b0*bb[j].b+c0;            while(p<=n&&da[p].c<=lim){                if(da[p].a>=da[i].a&&da[p].b>=bb[j].b)cnt++;                p++;            }            ans=max(cnt,ans);              if(bb[j].c<=lim)cnt--;                              }    }    printf("%d\n",ans);    return 0;}
0 0