1. 程式人生 > >牛客挑戰賽18th F Alice收集玩偶 二分 三分

牛客挑戰賽18th F Alice收集玩偶 二分 三分

pbo fir const double 題目 sub item oar describe

轉載: https://blog.csdn.net/m0_38013346/article/details/80425938

題目描述

Alice是個小女孩,最近經常睡得很晚起得也很晚。 她的母親希望她能戒掉這個壞習慣,所以對Alice說:“如果你早睡一天,我會給你一張粉紅色的貼紙。 如果你早起一天,我會給你一張橙色的貼紙。"
當Alice長大後,她成為了一個早睡早起的好女孩。 她已經收集了A張粉紅色的貼紙和B張橙色的貼紙。 但她不再喜歡貼紙。 所以她再也不會收集貼紙了。 有一天,她向媽媽抱怨她不喜歡貼紙了。 她的母親對她說:“那麽現在,你可以用x1張粉紅色貼紙和y1張橙色貼紙來換一只小貓玩偶,或者用x2張粉紅色貼紙和y2張橙色貼紙來換一只小狗玩偶。
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;  
}  

  


牛客挑戰賽18th F Alice收集玩偶 二分 三分