【描述】
有n个人,需要组成一个“冲金”队,来应付今年的noi,冲金的人数需要越多越好,但当然,需要满足一定的条件。对每个人有两个描述:h身高,w体重。我们定义一个函数Fi=A*(Hi-h) + B*(Wi-w),其中Hi,Wi表示第i个人的身高和体重,h,w表示选中队伍中的最小身高和最小体重,A,B为给出的常数。现在,学校领导的要求是找到一个队伍,满足所有队伍中的人的fi值均不超过C,并且在这个条件上找到队伍最大可能的人数。
【输入格式】
第一行一个数N
第二行三个数A,B,C
接下来N行,每行两个数Hi,Wi
【输出格式】
仅一行,为队伍最大可能的人数。
【样例输入】
8
1 2 4
5 1
3 2
2 3
2 1
7 2
6 4
5 1
4 3
【样例输出】
5
【数据范围】
N<=1000; A,B,C<=10000; Hi,Wi<=100000;
【分析】
预处理he[i]为a*h[i]+b*w[i]。
首先我们将所有的人按照h进行排序,然后从n到1枚举h最小的那个人。因为当前枚举的i的h在i~n中是最小的,那么包含i的队伍肯定是在i~n中挑选。那么我们要做的就是看用哪个人的w[i]最为最小的w。要注意我们的i是必须要取的,所以我们将i~n按照w排序,那么最为w的那个人的w值肯定要比i的小。那么我们只需要枚举比w[i]小的人即可。因为最小的h是确定的(h[i]),我们可以先算出来一个he1表示he-a*h,然后枚举w值不超过i的人,将he1维护成大根堆,如果最大的满足计算出来的数小于c那么比他小的肯定也满足。需要注意的是,i是必须要的人。那么我们如果发现he1值最大的是i了,当前枚举的是点j,而且函数值已经大于c,那么w值比j小的人肯定也不行。因为如果w比j小的人最为w最小的人存在,那么函数值肯定比j最为最小的人存在的时候大。(说的好混乱)。
然后我们就这么做就行啦!~一个排序,一个堆。
#include <stdio.h>
#define maxn 2010
int h[maxn],w[maxn],he[maxn],w1[maxn],he1[maxn],heep[maxn];
int i,j,k,n,m,s,max,a,b,c,t,top;
void init()
{
scanf("%d%d%d%d",&n,&a,&b,&c);
for (i=1;i<=n;++i) scanf("%d%d",&h[i],&w[i]);
}
void swap(int &a,int &b)
{
int k;
k=a; a=b; b=k;
}
void sort(int l,int r,int a[],int b[])
{
int i,j,k;
i=l; j=r; k=a[(l+r)>>1];
while (i<j)
{
while (a[i]<k) ++i;
while (a[j]>k) --j;
if (i<=j)
{
swap(a[i],a[j]);
swap(b[i],b[j]);
++i;
--j;
}
}
if (l<j) sort(l,j,a,b);
if (i<r) sort(i,r,a,b);
}
void insert(int p)
{
heep[++top]=p;
p=top;
while ((p>1)&&(he1[heep[p]]>he1[heep[p/2]]))
{
swap(heep[p],heep[p/2]);
p/=2;
}
}
void dele()
{
int p;
heep[1]=heep[top];
--top;
p=1;
while (((p*2<=top)and(he1[heep[p*2]]>he1[heep[p]]))or
((p*2+1<=top)and(he1[heep[p*2+1]]>he1[heep[p]])))
{
if (p*2+1<=top)
if (he1[heep[p*2]]>he1[heep[p*2+1]])
{ swap(heep[p],heep[p*2]); p=p*2; } else
{ swap(heep[p],heep[p*2+1]); p=p*2+1; } else
{ swap(heep[p],heep[p*2]); p=p*2; }
}
}
void work()
{
sort(1,n,h,w);
max=0;
for (i=1;i<=n;++i) he[i]=a*h[i]+b*w[i];
for (i=n;i>0;--i)
{
t=0;
for (j=n;j>=i;--j)
{
w1[++t]=w[j];
he1[t]=he[j]-a*h[i];
}
sort(1,t,w1,he1);
for (j=t;j>=1;--j)
if (w1[j]==w[i])
{
k=j;
break;
}
s=top=0;
int tt=0;
for (j=t;j>=k;--j)
if (he1[j]-b*w1[k]<=c) insert(j);
if (top>max) max=top;
for (j=k-1;j>=1;--j)
{
while ((he1[heep[1]]-b*w1[j]>c)&&(top>0))
{
if (heep[1]==t)
{
tt=1;
break;
}
dele();
}
if (tt) break;
if (he1[j]-b*w1[j]<=c) insert(j);
if (top>max) max=top;
}
}
}
int main()
{
freopen("team.in","r",stdin);
freopen("team.out","w",stdout);
init();
work();
printf("%d\n",max);
return 0;
}