HDU-4430-Yukari's Birthday-暴力+二分

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


.

你可能感兴趣的:(HDU-4430-Yukari's Birthday-暴力+二分)