题目描述
Alice是个小女孩,最近经常睡得很晚起得也很晚。 她的母亲希望她能戒掉这个坏习惯,所以对Alice说:“如果你早睡一天,我会给你一张粉红色的贴纸。 如果你早起一天,我会给你一张橙色的贴纸。"
当Alice长大后,她成为了一个早睡早起的好女孩。 她已经收集了A张粉红色的贴纸和B张橙色的贴纸。 但她不再喜欢贴纸。 所以她再也不会收集贴纸了。 有一天,她向妈妈抱怨她不喜欢贴纸了。 她的母亲对她说:“那么现在,你可以用x 1张粉红色贴纸和y 1张橙色贴纸来换一只小猫玩偶,或者用x 2张粉红色贴纸和y 2张橙色贴纸来换一只小狗玩偶。
Alice听了妈妈的话开心了起来,她想收集尽可能多的玩偶。
现在,请您计算 Alice 可以获得的玩偶数量最多是多少(玩偶都是完整的,没有半只玩偶这类的东西)。
当Alice长大后,她成为了一个早睡早起的好女孩。 她已经收集了A张粉红色的贴纸和B张橙色的贴纸。 但她不再喜欢贴纸。 所以她再也不会收集贴纸了。 有一天,她向妈妈抱怨她不喜欢贴纸了。 她的母亲对她说:“那么现在,你可以用x 1张粉红色贴纸和y 1张橙色贴纸来换一只小猫玩偶,或者用x 2张粉红色贴纸和y 2张橙色贴纸来换一只小狗玩偶。
Alice听了妈妈的话开心了起来,她想收集尽可能多的玩偶。
现在,请您计算 Alice 可以获得的玩偶数量最多是多少(玩偶都是完整的,没有半只玩偶这类的东西)。
输入描述:
输入的第一行将包含一个整数T,表示您应该处理的查询数量。 对于每个查询,给出一行包含六个整数A,B,x1,y1,x2,y2,表示上述语句中的数值。
输出描述:
对于每个查询,输出一行表示答案的整数。
示例1
输入
4 10 10 2 3 3 2 10 14 2 3 3 2 10 15 2 3 3 2 1000000000 999999999 1 4 10000 3
输出
4 4 5 250018751
说明
样例里第二个数据的解释:选择换2只小猫和2只小狗,那么粉红色的贴纸就刚好用完了,2*2+2*3=10张贴纸,橙色的贴纸用了3*2+2*2=10张,还剩4张,但是已经没有粉红色贴纸可以搭配了,也沒有其他方案能换更多个玩偶;第三个数据解释:选择换5只小猫是最佳的,这样刚好全部贴纸都用完了,5*(2+3)=10+15=25.
备注:
1 ≤ T ≤ 105 1 ≤ A, B, x1, y1, x2, y2 ≤ 2 x 109
官方题解:
分类讨论的思路没想出来, 但是这是一个单峰函数,需要求最大值.
我们考虑用三分查找答案的思想来解决
三分查找答案 :
我们都知道 二分查找 适用于单调函数中逼近求解某点的值。
扫描二维码关注公众号,回复:
1277286 查看本文章
如果遇到凸性或凹形函数时,可以用三分查找求那个凸点或凹点。
下面的方法应该是三分查找的一个变形。
给出三分的模板代码:
while(l + eps < r) { double lm = l + (r - l) / 3,rm = r - (r - l) / 3; if(check(lm) < check(rm)) l = lm; else r = rm; }
但是三分一般需要浮点数.
对于这题就需要一点技巧了.首先用浮点数进行三分.
最终能保证是答案一定在[l,r]之间.注意这里的l和r需要分别向下取整和向上取整数.
代码
#include<bits/stdc++.h> #define eps 1e-6 using namespace std; typedef long long ll; const ll inf = 1ll<<33; ll A,B,x11,y11,x22,y22; double cal(double mid) { return mid + min((A-x11*mid)/x22,(B-y11*mid)/y22); } int main() { int caset;scanf("%d",&caset); while(caset--) { scanf("%lld%lld%lld%lld%lld%lld",&A,&B,&x11,&y11,&x22,&y22); double l = 0,r = min(A/x11,B/y11); while(l + eps < r) /// 这里也可以将eps设的相对较大(如1000),保证解一定在[l,r]中 { double lm = l + (r - l) / 3,rm = r - (r - l) / 3; if(cal(lm) < cal(rm)) l = lm; else r = rm; } ll le = floor(l),ri = ceil(r); le = max(le,0ll);ri = min(ri,min(A/x11,B/y11)); ll ans = 0; for(ll i=le;i<=ri;i++) { ans = max(ans,i + min((A - i*x11)/x22,(B - i*y11)/y22)); } printf("%lld\n",ans); } return 0; }
思路二 : 考虑二分来解决这个问题
首先需要先按照对x1和x2进行从小到大的排序,
于是保证了x1 <= x2,
如果 y1 <= y2 则全部取 x1,y1是最优的情况.
如果y1 > y2
则这个时候我们考虑去二分查找答案ans.
假设 小狗玩偶的个数为y ,那么小猫玩偶的个数为x = ans - y
注意到x1 < x2 且 y1 > y2
在粉红贴纸没有超的情况下我们去最大化小狗玩偶的个数y
这样使用的橙色贴纸的数量一定是最少的,
我们再去验证这个时候使用的橙色贴纸有没有超出B
代码
#include<bits/stdc++.h> #define mp make_pair #define fi first #define se second #define debug(x) cerr<<#x<<" = "<<(x)<<endl #define eps 1e-8 #define pi acos(-1.0) using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll> pll; const int MAXN=(int)1e5+5; const int MOD=(int)1e9+7; int n,m; pii a,b; bool isok(int x){ if(1ll*x*a.fi>n||1ll*x*b.se>m)return 0; int num; num=(n-x*a.fi)/(b.fi-a.fi); return 1ll*(x-num)*a.se+num*b.se<=m; } int main() { int t; scanf("%d",&t); while(t--){ scanf("%d%d%d%d%d%d",&n,&m,&a.fi,&a.se,&b.fi,&b.se); if(a>b)swap(a,b); if(a.se<=b.se){ printf("%d\n",min(n/a.fi,m/a.se)); } else { int l=0,r=(int)2e9,ans; while(l<=r){ int mid=(l+r)>>1; if(isok(mid)){ ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); } } return 0; }