标签:des style blog http java color 使用 os
18 111 1111
1 17 2 10 3 10
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef __int64 LL;
LL sum(LL k,LL r,LL n) //求∑k^i
{
LL ans=0,t=k;
for(int i=0;i<r;i++)
{
ans+=t;
t*=k;
if(ans>n) return n+1; //∑k^i的一部分值已超出n
//就不用再计算,返回n+1即可
}
return ans;
}
bool judge(LL r,LL _l,LL _r,LL &k,LL n) //使用二分求出当前r对应的k值
{
LL t;
while(_l<=_r)
{
k=(_l+_r)/2;
t=sum(k,r,n);
if(t==n)
{
return true;
}
else if(t<n) _l=k+1;
else if(t>n) _r=k-1;
}
return false;
}
int main()
{
LL n;
while(scanf("%I64d",&n)!=EOF)
{
LL R=1,K=2;
for(;K<(n+2)/2;K<<=1) //求出最大的圈数,即每圈放两个蜡烛
{
R++;
}
LL r,k;
LL rr=1e7,kk=1e7,_l=2,_r=n,t;
for(r=1;r<=R;r++)
{
_l=2,_r=(LL)pow(double(n+1),1.0/(double)r); //给出左右边界
if(judge(r,_l,_r,k,n)) //求出当前r下,最中心不放蜡烛的k
{
if(r*k<rr*kk||(r*k==rr*kk&&r<rr))
rr=r,kk=k;
}
if(judge(r,_l,_r,k,n-1)) //求出当前r下,最中心不放蜡烛的k
{
if(r*k<rr*kk||(r*k==rr*kk&&r<rr))
rr=r,kk=k;
}
}
printf("%I64d %I64d\n",rr,kk);
}
return 0;
}
/*
题目的意思是,一个蛋糕上放n跟蜡烛,第一圈假设放k个,那么第二圈最多放k*K个……
直到所有的蜡烛都放完,每圈最少放2根,最中间可以放一根也可以不放,求圈数r和k,
如果有多种情况,那么保证r*k最小,如果还有多种情况,保证r最小。
由于每圈最少放两根,为了保证r*k最小,那么我们保证除了最后一圈,其他都放满,这样
我们就能求出最大的圈数R,那么我们就可以枚举圈数r来计算慢去情况的k
这里我们需要用二分来查找最小的k,k的最小值为2,那么左边界为2,接下来我们求右边界,
利用等比数列的求和公式sum=a1*(k^r-1)/k-1=k*(k^r-1)/k-1;这里sum=n和r均是已知值,来求k是可以做到的
但是求解起来比较困难,所以我们要使用放缩的方法,这里sum'=k^r-1,可以看到sum'<sum=n
那么我们用n来代替sum',之后得到的k'是大于k的,扩大了寻找范围,但是不会漏掉情况
那么右边界的求法就是r=(LL)pow(double(n+1),1.0/(double)r);
由于中间可以放也可以不放,那么我们就分开来求k就可以了,然后再比较得出最优情况。
*转载请注明出处,谢谢。
*/
hdu 4430 Yukari's Birthday(二分),布布扣,bubuko.com
hdu 4430 Yukari's Birthday(二分)
标签:des style blog http java color 使用 os
原文地址:http://blog.csdn.net/knight_kaka/article/details/38234913