题目传送-Luogu4165
题目传送-BZOJ1071
题意:
有\(n\)个物品,每个物品有属性\(a,b\)。
同时给出整数\(A,B,C\)
从\(n\)个物品中选出最多的物品,使得对于其中任意一个物品\(i\),有\(A*(a_i-Min_a)+B*(b_i-Min_b)\le C\)
其中\(Min_a\)为选中的物品中\(a\)的最小值,\(Min_b\)同理
$n \le 5000 $,所有运算在长整型范围中.
题解:
本题的实质是取若干数,使其满足如下不等式:
1.\(A*(a_i-Min_a)+B*(b_i-Min_b)\le C\)
2.\(a_i\ge Min_a\)
3.\(b_i\ge Min_b\)
很容易想到\(n^3\)暴力,枚举\(Min_a\),\(Min_b\),再扫一遍考虑优化它。
我们发现,如果同时满足1,3,那么可以得出4.\(a_i \le Min_a+ \lfloor \frac{C}{A} \rfloor\)
注意到这是可以逆推回去的,那么对于b的限制就转换成对于a的限制了
那么如果确定了\(Min_a\)则\(a\)的范围也确定了
再对1移项整理,得\(A*a_i+B*b_i \le C+A*Min_a+B*Min_b\)
定义\(border=C+A*Min_a+B*Min_b\)
所以枚举\(Min_a\),\(border\)就可以\(n^2\)得出答案了
过程:
刚开始的时候没有发现4是充要的。。然后写出了下面两行注释,发现这个是错的。
因为虽然一开始符合条件,但随着枚举的进行却会不符合
代码:
const int N=5010;
int n; ll A,B,C;
struct PEOPLE {
ll a,b,v;
inline void in() {
read(a); read(b); v=a*A+b*B;
}
bool operator < (const PEOPLE &_)const {
return b<_.b;
}
}p[N],q[N];
bool cmp(const PEOPLE &x,const PEOPLE &y) {
return x.v<y.v;
}
signed main() {
read(n); read(A); read(B); read(C);
for(int i=1;i<=n;i++) p[i].in(),q[i]=p[i];
sort(p+1,p+n+1); sort(q+1,q+n+1,cmp);
int ans=0;
for(int i=1;i<=n;i++) {
int L=p[i].a,R=p[i].a+C/A;
int p1=1,ret=0;
for(int j=1;j<=n;j++) {
while(p1<=n && q[p1].v<=C+A*p[i].a+B*p[j].b) {
if(L<=q[p1].a && q[p1].a<=R) ++ret;
// if(q[p1].a>=p[i].a) ++ret;
++p1;
}
if(L<=p[j-1].a && p[j-1].a<=R) --ret;
// if(p[j-1].a>=p[i].a && Calc(p[j-1])<=C+A*p[i].a+B*p[j].b) {assert(p[j-1].a>C/A+p[j].a); --ret;}
ans=max(ans,ret);
}
}
printf("%d\n",ans);
return 0;
}
用时:2h