hdu4803 Poor Warehouse Keeper

给定两个数字显示板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=4803
 
 
 1 #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 }
View Code

 

posted @ 2015-08-18 16:07  astoninfer  阅读(185)  评论(0编辑  收藏  举报