[bzoj1071] [SCOI2007]组队
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
Solution
把式子化开,可以得到:
\[A\cdot h+B\cdot s\leqslant A\cdot mnh+B\cdot mns+C
\]
然后我们就得到了一个\(O(n^3)\)的做法:枚举\(mnh,mns\),然后枚举每一个合不合法。
考虑这个怎么优化,首先枚举最小值的时候从小到大枚举,那么枚举\(mns\)的时候不等式的右边就会单调递增,那么我们可以按照左边排序,然后从小到大加。
注意到这里还要两个限制:\(h\geqslant mnh,s\geqslant mns\),然后就有一个很神奇的做法:
先不考虑\(s\)带来的影响,那么对于\(h\),显然要满足\(mnh\leqslant h \leqslant mnh+C/A\),然后把满足这些条件的加进去,
对于\(s\),如果满足以上条件,但是\(s<mns\),那么就把这个删掉。
然后合法的一定是连续一段,所以上面的做法是对的。
可以发现以上都是单调的,所以总复杂度\(O(n^2)\)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 2e5+10;
int n,A,B,C,tx[maxn],ans,q[maxn];
struct data {int x,y,sum;}a[maxn],b[maxn],c[maxn];
int cmpx(data x,data y) {return x.x<y.x;}
int cmpy(data x,data y) {return x.y<y.y;}
int cmpsum(data x,data y) {return x.sum<y.sum;}
signed main() {
read(n),read(A),read(B),read(C);
for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y),b[i].x=c[i].x=a[i].x,b[i].y=c[i].y=a[i].y;
for(int i=1;i<=n;i++) c[i].sum=c[i].x*A+c[i].y*B;
sort(a+1,a+n+1,cmpx);
sort(b+1,b+n+1,cmpy);
sort(c+1,c+n+1,cmpsum);
for(int i=1;i<=n;i++) {
int mn=a[i].x,mx=a[i].x+C/A,p1=0,p2=0,cnt=0;
for(int j=1;j<=n;j++) {
int lim=C+a[i].x*A+b[j].y*B;
while(p1<n&&c[p1+1].sum<=lim)
p1++,cnt+=(c[p1].x>=mn&&c[p1].x<=mx);
while(p2<n&&b[p2+1].y<b[j].y)
p2++,cnt-=(b[p2].x>=mn&&b[p2].x<=mx);
ans=max(ans,cnt);
}
}write(ans);
return 0;
}