【题解:JSOI2009 配菜】

JSOI上总能找到些神奇的题,,,,,

描述
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<SV≤100, 大袋装原料的尺寸;

PV,PM<PV≤100, 大袋装原料的价格。

输出
输出文件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,用DP发现似乎布星,因为对于每一种原料,它的需要量与已有量,以及大小包的性价比之间的关系过于复杂,而最终答案又受各种原料的数据影响。
也就是说,这大小为m的钱的分配需要是最优解,而每一分钱又尽量要花到刀刃上,且m怎么分配是受到各调料的6个参数的影响的。
所以,要考虑的东西太多,DP还真做不了(六维超级DP????? ) 。
那么怎么办呢?
我们考虑到,如果已知要做k道菜,那么所花钱的最小值是可以暴力求出来的,而且在k2>k1的时候,ans(k1)<=ans(k2)是恒成立的,因为我们保证暴力出来的一定是做k道菜的最优解。

所以二分的思路就很清楚了,开出变量L和R,假设要做mid道菜,暴力计算最小花费,再判断最小花费与m的关系,就很明确了。

有一个非常值得注意的地方是,这里的mid是菜的数量,判断标准是ans(mid)与m的关系,换句话说,mid是要参与二分的运算的,mid的大小与时间复杂度有直接得不能再直接的关系,所以注意,R不能开太大!
介于上句话的重要性,我们再强调一下:
R不能开太大!!!!!!!
如何证明这一点呢?

在学校OJ上提交老是TLE,怀疑 人生 被卡常。运用各种玄学操作(包括不能本及调试的超级读优,还有普通写优,还有结构体封装函数,就差手打开关了)想要提高运行速度,结果发现是因为R不能开太大时,真的是悲从中来。

不多说了,贴代码:

#include<bits/stdc++.h>
using namespace std;
inline char nc(){//超级读优,但无法本机调试
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
inline void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
int n,m;int l=0,r=100001;
const int N=101;
int x[N],y[N],sm[N],sv[N],pm[N],pv[N];
struct node{
	inline int solve(int idx,int d){//贪心找最优方案
	 	int ans=1e9;
	 	int k=d/pm[idx];
		 if(d%pm[idx]) k+=1;
		for(;k>=0;k--){
	 		int w=k*pv[idx],need=d-k*pm[idx];
	 		if(need>0){
	 			int s=need/sm[idx];
	 			if(need%sm[idx]) s++;
	 			w+=s*sv[idx];
			}
	 		ans=min(ans,w);
	 }
	 	return ans;
	}
	inline bool check(int mid){
		int rest=m;
		for(int i=1;i<=n;i++){
			int d=mid*x[i]-y[i];
			if(d<=0) continue;
			rest-=solve(i,d);
			if(rest<0) return 1;
		}
		return 0;
	}	
}AC; 

int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		x[i]=read(), y[i]=read();
		sm[i]=read(),sv[i]=read();
		pm[i]=read(),pv[i]=read();
	}
	int mid;
	while(l+1<r){
		mid=(l+r)>>1;
		if(AC.check(mid)) r=mid;
		else l=mid;
	}
	if(AC.check(r)) write(l);
	else write(r);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43263852/article/details/85852603