Lisa是一家餐厅的女服务员。今晚是它的生日,所以Lisa请求厨师长准备特别餐来招待她的朋友。厨师长的晚餐由N种烹调原料做成。为了准备晚餐上的一道菜,各种烹调原料他都需要一些。
有些烹调原料可以从厨房里得到, 剩下的烹调原料Lisa将会去杂货商店买。商店有全部所需的烹调原料,有大袋装的和小袋装的。Lisa有M美元,想用M美元让厨师长做出最多的菜。
输入
输入文件kuhar.in第一行两个整数:N、M,1≤N≤100,1≤M≤100 000。 第2…N行:每行包含6个正整数,按顺序描述每种烹调原料:
X,10≤X≤100,一道菜里需要的这种烹调原料数目;
Y,1≤Y≤100, 厨房已有这种烹调原料数目;
SM,1≤ SM<100,小袋装原料的尺寸;
PM,10≤PM<100, 小袋装原料的价格;
SV,SM
PV,PM
输出
输出文件kuhar.out中一个整数,表示厨师长能做出最多菜的数目。
样例输入
2 100
10 8 10 10 13 11
12 20 6 10 17 24
样例输出
5
【样例解释】
样例中,Lisa花99美元买三个小包装袋和一个大包装袋的第一种配料、一个小包装袋和两个大包装袋的第一种配料(310+111+110+224=99)。
这样的话,厨师长就会有51个(8+310+113)单位的第一种烹调原料,60个(20+16+217)单位的第二种烹调原料。
分析:刚开始看到思路很乱,觉得DP贪心都可以来一发【事实好像确实是这样的】
而我觉得二分还是挺好想到的,而研究的问题确实符合单调性,说到底,就是我有的钱,相对于我现在要买做的菜需要的材料的钱更多还是更少的问题。这样二分的模型基本抽象出来了,按这个想法只需稍加改动转化为可行与不可行就成为了check函数。而check里面一定要保证最优,所以要计算买若干食材需要的钱的最小值。数据规模并不大,枚举和背包问题都不大,这里我写了枚举。枚举k~0袋大包装,打擂台算出最小值。
呈上我Naive的代码
#includeusing namespace std; #define N 100000000 int n,m,ans,x[110],y[110],ss[110],sp[110],bs[110],bp[110]; int l,r,mid; int check(int middle) { int money=m; for(int i=1;i<=n;i++) { int ret=N; int need=middle*x[i]-y[i]; int k=need/bs[i]; if(bs[i]*k //这里是为了防止除法直接舍掉零头,所以验证了一下。有余数的情况下实际需要的应该+1; k++; while(k>=0) { int j=(max(need-bs[i]*k,0))/ss[i]; if(ss[i]*j+k*bs[i] //同上理 j++; ret=min(ret,k*bp[i]+j*sp[i]); k--; } money-=ret; if(money<0)//小小地剪枝 return 0; } return 1; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%d%d%d%d",&x[i],&y[i],&ss[i],&sp[i],&bs[i],&bp[i]); l=0;r=100000;//这里r不能太大,因为mid的大小与时间复杂度是有关的,check里k的那个循环复杂度大概是mid的百分之一,r太大的话,比较刁钻的数据就会T while(l<=r) { mid=(l+r)/2; if(check(mid)) { l=mid+1; ans=mid; } else r=mid-1; } printf("%d",ans); return 0; }