[纠结了一天的题目= =]团结的队伍
【描述】
有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; }