牛客挑战赛18th F Alice收集玩偶 二分 三分

题目描述 

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


官方题解:



分类讨论的思路没想出来, 但是这是一个单峰函数,需要求最大值.

我们考虑用三分查找答案的思想来解决


三分查找答案   : 

我们都知道 二分查找 适用于单调函数中逼近求解某点的值。

如果遇到凸性或凹形函数时,可以用三分查找求那个凸点或凹点。

下面的方法应该是三分查找的一个变形。



给出三分的模板代码:

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;
}

猜你喜欢

转载自blog.csdn.net/m0_38013346/article/details/80425938
今日推荐