地址: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;
}
.