题解:P13013 [GESP202506 五级] 奖品兑换
Clouds_dream · · 题解
前言
一道很好的二分练手题。
题目内容
题目传送门
题目分析
我们假设用第一种方式兑换了
因为每次兑换至少消耗
对于给定的
-
a \cdot x + b \cdot (k - x) \le n -
b \cdot x + a \cdot (k - x) \le m
整理得:
-
(b-a) \cdot x \ge b \cdot k - n $ $(b > a) -
(b-a) \cdot x \le m - a \cdot k $ $(b > a)
计算
边界处理:
- 当
a = b 时,直接记录答案。 - 当
a < b 时,先计算总券数是否够,然后计算x 的区间。
上代码(知道你们直接看这个)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define fst ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define prq priority_queue
#define uns unordered_set
#define freopen freopen(".in","r",stdin);freopen(".out","w",stdout);
const int P = 998244353;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6+10, M = 1e8 + 10;
int __lcm(int a,int b){return a/__gcd(a,b)*b;}
int n,m,a,b;
int ans=0;
signed main()
{
fst
cin>>n>>m>>a>>b;
if(a>b)swap(a,b);//确保a<=b
int l=0,r=min(n/a,m/a);//左右区间
while(l<=r){
int mid=(l+r)/2;
if(a==b){
ans=mid;
l=mid+1;
}//情况1
else{
if((a+b)*mid>n+m){
r=mid-1;
continue;
}
int mi=0;
if(b*mid>n){
mi=(b*mid-n+b-a-1)/(b-a);//左端点
}
int ma=(m-a*mid)/(b-a);
ma=min(ma,mid);//右端点
if(ma>=0&&mi<=ma){
ans=mid;
l=mid+1;
}
else{
r=mid-1;
}
}//情况2
}
cout<<ans;
return 0;
}
UPD
2025.7.2 感谢 @pika_ 大佬指出的错误。