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(二分)
原文:http://blog.csdn.net/knight_kaka/article/details/38234913