给定两个数字显示板A, B和两个按钮,按下按钮使得其对应数字显示增加1。
另,B显示板只显示其实际值的整数部分。两显示器对应的实际值有一个比值p。
按下A板上的按钮, A板上显示的数增加1到a + 1, p不变,B板上的数字更新为(int)(b * (a + 1) / a)。
按下B板上的按钮,A板上上显示的数值不变,B 板加1 到b + 1,p更新为(b + 1) / a。
给定目标状态(a1, b1),问至少经过多少次按下按钮可从初始状态(1, 1)到达该状态。
若不可达输出-1。
显然按下A板按钮使得B板数值成比例增加,比值为p,按下B板数值使得比例增加。
比例增加过程不可逆,状态不可达当且仅当a1 < b1。
首先从A板数组从1增加到a1至少需要a1 - 1次操作,这与B板的状态无关。
而A板的数值变化会引起B板成倍增加,考虑到f(i) = (i + 1) / i是严格递减函数。
直观上我们有应该尽可能把按A板的操作提前,这样B板上的数值就会尽快接近目标值。
注意到比值p<(b + 1) / a,我们尽可能向该值靠近,从1开始。
然后随着A板数值增大,逐步逼近该值,记录下B板的操作次数,即可解决此题。
浮点数执行近似运算,导致误差,本题用分数表示有理数(比值)。
acm.hdu.edu.cn/showproblem.php?pid=48031 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 typedef __int64 LL; 7 8 LL a, b; 9 10 LL gcd(LL a, LL b){ 11 if(!b) return a; 12 return gcd(b, a % b); 13 } 14 15 void solve(){ 16 if(b < a){ 17 printf("-1\n"); 18 return; 19 } 20 LL lhs = 1, rhs = 1; 21 //rhs :: denominator 22 //lhs :: numerator 23 LL cnt = a - 1; 24 //operations required for A 25 for(int i = 1; i <= a; i++){ 26 LL f = (b + 1) * i * lhs - a * rhs, g = a * lhs; 27 LL k = (f % g == 0 ? f / g - 1 : f / g); 28 cnt += k; 29 //extra operations required for B 30 rhs += k * lhs; 31 LL GCD = gcd((i + 1) * rhs, i * lhs); 32 rhs = rhs * (i + 1) / GCD; 33 lhs = lhs * i /GCD; 34 } 35 printf("%I64d\n", cnt); 36 } 37 38 int main(){ 39 while(~scanf("%I64d%I64d", &a, &b)){ 40 solve(); 41 } 42 return 0; 43 }
时间: 2024-10-10 03:41:46