地址:http://acm.hdu.edu.cn/showproblem.php?pid=4430
题意:
给你一个n 18 ≤ n ≤ 10 12.
你输出r,k,首先满足 1+k^1+k^2+...+k^r = n或者n+1并且k的范围是k>=2; //如果多个满足 取r*k最小的,如果还有多个,取r最小的
从k最小为2可知,r最大不超过40,因为1+ 2^40 接近10^12
并且显然公式左边是等比数列,化简得, (k^r-1)/(k-1) = n
显然,当k>1对于左边是一个 单调递增的的函数,那么当r,n确定,我们只需要 二分k 就可以了
k的范围是 【2,10^12】
有一点就是 判断函数 本应该写 if ((pow(k,r+1)-1)/(k-1)-n >eps )
然而当时脑残了不知道想了什么 居然把k-1移到右边,变成pow(k,r+1)-1)-(k-1)*n.. //当k=n=10^12的时候,会爆掉!
主要就是注意pow这里判断相等和大于要用 eps.....并且注意不要把k-1放到右边就可以了!
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <cfloat> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; __int64 maxx= 9223372036854775807; #define eps 0.01 __int64 ans_r; __int64 ans_k; int main() { __int64 n; __int64 slove1 (__int64 n); //n+1 while( scanf("%I64d",&n)!=EOF) { // maxx=n-1; maxx= 9223372036854775807; ans_r=1; ans_k=n-1; slove1(n); slove1(n+1); printf("%I64d %I64d\n",ans_r,ans_k); } return 0; } __int64 ok(__int64 k,__int64 r,__int64 n) { if ((pow(k,r+1)-1)/(k-1)-n >eps ) return 1; else return 0; } __int64 slove1(__int64 n) { int i; for (i=1;i<=40;i++) { __int64 l=2; __int64 r=pow(10.0,12); while(l<r) { __int64 mid=(l+r)/2; if (r-l==1) { if ((! (fabs((pow(r,i+1)-1)/(r-1)-n)<eps) ) ) r=l; break; } if (ok(mid,i,n)) r=mid-1; else l=mid; } if ( fabs((pow(r,i+1)-1)/(r-1)-n)<eps ) { __int64 tmp=i*r; if (tmp<maxx) { maxx=tmp; ans_r=i; ans_k=r; } else if(tmp==maxx) { if (i<ans_r) { ans_r=i; ans_k=r; } } } } return 0; }
.