牛客挑戰賽18th F Alice收集玩偶 二分 三分
阿新 • • 發佈:2018-06-02
pbo fir const double 題目 sub item oar describe
當Alice長大後,她成為了一個早睡早起的好女孩。 她已經收集了A張粉紅色的貼紙和B張橙色的貼紙。 但她不再喜歡貼紙。 所以她再也不會收集貼紙了。 有一天,她向媽媽抱怨她不喜歡貼紙了。 她的母親對她說:“那麽現在,你可以用x1張粉紅色貼紙和y1張橙色貼紙來換一只小貓玩偶,或者用x2張粉紅色貼紙和y2張橙色貼紙來換一只小狗玩偶。
Alice聽了媽媽的話開心了起來,她想收集盡可能多的玩偶。
現在,請您計算 Alice 可以獲得的玩偶數量最多是多少(玩偶都是完整的,沒有半只玩偶這類的東西)。
轉載: 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收集玩偶 二分 三分