【题意】
给定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溢出。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }