HDU 4430Yukari's Birthday(枚举+二分)

【题意】

给定N,把N或者N+1,表示成

1+k+k^2+...+k^r,求使k*r最小的r k.

N<=10^12

【分析】

就是把一个数n表示成k>=2进制数,有r+1个1。

考虑把n分解为2进制时,最多也就2^40,r<40。并且r越大,k越小。

那么枚举r,二分求k(k并不总是存在)。求最小值即可。

【Mark】

注意,求k进制下r+1个1时,会越界溢出。。。。res*k+1溢出。

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #define LL long long
 5 
 6 
 7 LL get(LL r,LL k,LL n)
 8 {
 9     //printf("r = %I64d k = %I64d  ",r,k);
10     LL res = 0;
11     while (r--)
12     {
13         if (res > n / k)
14         {
15             res = n + 1;
16             break;
17         }
18         res = res*k + 1;
19     }
20     //printf("res = %I64d\n",res);
21     return res;
22 }
23 
24 LL calc(LL rr,LL n)
25 {
26     LL l = 2,r = n - 1;
27     while (l <= r)
28     {
29         LL m = (l + r)/2;
30         LL tmp = get(rr,m,n);
31         if (tmp == n)
32             return m;
33         if (tmp < n){
34             l = m + 1;
35         }else{
36             r = m - 1;
37         }
38     }
39     return 0;
40 }
41 int main()
42 {
43     LL n;
44     //n = 1000000000000;
45    // printf("%I64d\n",n);
46     //printf("%I64d\n",get(40,9999999999));
47     while (scanf("%I64d",&n)==1)
48     {
49         LL ans1 = 1;
50         LL ans2 = n-1;
51         for (LL r = 1;r<=50;r++)
52         {
53             LL k = calc(r + 1,n);
54            // printf("ans == %I64d %I64d\n",r+1,k);
55             if (k>0 && k * r < ans1*ans2)
56             {
57                 ans1 = r;
58                 ans2 = k;
59             }
60             k = calc(r+1,n+1);
61             if (k>0 && k*r < ans1*ans2)
62             {
63                 ans1 = r;
64                 ans2 = k;
65             }
66         }
67         printf("%I64d %I64d\n",ans1,ans2);
68     }
69     return 0;
70 }
hdu4430

 

转载于:https://www.cnblogs.com/wangsouc/articles/3302600.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值