一天,欧姆诺诺姆来到了朋友家里,他发现了许多糖果。有蓝色和红色两种。他知道每颗红色糖果重Wr克,每颗蓝色糖果重Wb克。吃一颗蓝色糖果会给他带来Hb的欢乐值,吃一颗红色糖果会给他带来Hr的欢乐值。
欧姆诺姆最多只能吃C克的糖果,而且每一颗糖果不能只吃一半。现在他想通过吃蓝色和红色的糖果来获得最大的欢乐值。
样例解释:每一种糖果吃两颗即可。
Input单组测试数据。
输入占一行有四个整数C,Hr,Hb,Wr,Wb (1≤C,Hr,Hb,Wr,Wb≤10^9).Output输出最大可能获得的欢乐值。Sample Input
样例输入1 10 3 5 2 3Sample Output
样例输出1 16
题意:中文题,题意就不说了;
思路:刚开始看题时,我想大家可能和我一样都是,先想到的是dp,完全背包吧,但是你在一看数据范围,打消这个念头;我又认真看题,找到wr和wb的最小公倍数,因为只有当他们重量一样多时,看看谁提升的提升欢乐值多,让c-c%他们的最小公倍数,这部分用提升欢乐值大的一方,其余的 c%最小公倍数 这部分枚举,枚举其中一个的数量,因为根据题意可以列来二元一次方程组,但是其中一个是不等式,这样的话,只要知道其中一个的数量,另一个数量就是确定的,枚举其中一个的数量,找欢乐值最大的结果,但是枚举的范围又该怎么确定啊?
数据范围为10^9,你要想用枚举的话,显然要优化到 根号c 或 log 级别的运算
这时候我们就该缩小其中一个数量的范围了,设重量为wr的为x个,重量为wb的为y个,方程 wr*x + wb*y = c,
情况一:当 wr的重量大于等于sqrt(c) 的话,那么枚举x,范围为0 ~ sqrt(c);
情况二:当wb的重量大于等于sqrt(c)的话,那么枚举y,范围为0 ~ sqrt(c);
情况三:当wr和wb的重量都小于sqrt(c)的话,wr*wb <= c。我们选wb个r和wr个b,这时候重量是一样的,但收益 一个是 wb*hr 另一个为wr*hb,这时候假设收益较小的为 r的话,那么r的数量一定不超过wb,否则就可以整体换成b了 (这里其实和我上面找wr和wb的最小公倍数的思路是相似的) ,所以r的数量 < wb < sqrt(c);
所以整体时间复杂度为 sqrt(c);对了,在代码中还有一些数据处理,代码中会有解释
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
ll c;
ll fff(ll k,ll w1,ll w2,ll h1,ll h2) // w1是要枚举的对象;
{
ll i,j;
ll Max_ans = 0;
for(i=0;i<=k;i++)
{ // 数据范围要用longlong因为w1*i可能会大于int型
if(w1*i<=c) // 一开始我是加的下面y<0时的条件;一直看不出和这个条件有啥区别;
{ // 现在我知道了,-1/2 可能在我们的印象中的结果为负数,但是在计算机中它的结果是0;
ll y = (c - w1*i)/w2; // 所以你必须要用上面的那个式子,来判断有没有超过c的范围;
//if(y<0)
//continue;
Max_ans = max(Max_ans,h1*i+h2*y);
}
}
return Max_ans;
}
int main()
{
ll i,j;
ll hr,hb,wr,wb;
while(~scanf("%lld%lld%lld%lld%lld",&c,&hr,&hb,&wr,&wb))
{
ll k = (ll)sqrt(c*1.0);
if(wr>k) // 情况一
printf("%lld\n",fff(k,wr,wb,hr,hb));
else if(wb>k) // 情况二
printf("%lld\n",fff(k,wb,wr,hb,hr));
else // 情况三
{
double t1 = (hb*1.0)/(wb*1.0);
double t2 = (hr*1.0)/(wr*1.0);
if(t1>t2)
printf("%lld\n",fff(k,wr,wb,hr,hb));
else printf("%lld\n",fff(k,wb,wr,hb,hr));
}
}
return 0;
}
法二:
#include <bits\stdc++.h>
using namespace std;
int main()
{
long long ans, c, wr, wb, hr, hb;
int lala = 10000000;
while(~scanf("%lld%lld%lld%lld%lld", &c, &hr, &hb, &wr, &wb))
{
ans = 0;
for(long long i=0;i<lala;++i)
{
if(i*wr<=c)
ans = max(ans ,i*hr+(c-i*wr)/wb*hb);
if(i*wb<=c)
ans = max(ans ,i*hb+(c-i*wb)/wr*hr);
}
printf("%lld\n",ans);
}
}