这一题要求all of its digits become 1,所以在base B下,假设N可以表示成p位数,这个数的值就是一个等差数列,因为N是long long范围,p最多为64。
记,因为B>1,给定p时,求导可以得出f(B)是单调增的。因此在给定p时,可以通过二分查找得出B的值。
这一题小数据我在二分的时候用除法比较abs(f(B))<1e-7居然WA了,不造为何。最后只能直接比较乘积,不会有精度损失。
小数据代码如下。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
using namespace std;
//2017 RoundE Problem B. Beautiful Numbers
int T;
long long N;
int P;
long long ans;
int calnum(int base)
{
int cnt=0;
int num=N;
while(num>0)
{
int bit=num%base;
num=num/base;
if(bit==1)
{
cnt++;
}
else
{
return -1;
}
}
return cnt;
}
long long power(long long base,int p)
{
long long ret=1;
for(int i=0;i<p;i++)
{
ret*=base;
}
return ret;
}
long long fun(long long base,int p)
{
//return 1.0*(1-pow(base,p))/(1-base);
return power(base,p)-1;
}
long long binarysearch(int p)
{
long long left=2;
long long right=N;
long long mid=(left+right)/2;
int cnt=0;
while(left<=right)
{
mid=(left+right)/2;
//double tmp=fun(mid,p);
long long tmp=fun(mid,p);
//cout<<left<<" "<<right<<" "<<mid<<" "<<tmp<<endl;
//if(abs(tmp-N)<1e-7)
if(tmp==N*(mid-1))
//if(abs(log(tmp)-log(N)-log(mid-1))<1e-7)
{
return mid;
}
if(tmp>N*(mid-1))
//if(log(tmp)-log(N)-log(mid-1)>0)
{
right=mid-1;
}
else if(tmp<N*(mid-1))
//else if(log(tmp)-log(N)-log(mid-1)<0)
{
left=mid+1;
}
cnt++;
// if(cnt>10)
// {
// break;
// }
}
return -1;
}
int main()
{
freopen("B-large-practice.in","r",stdin);//input.txt
freopen("output.txt","w",stdout);
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
scanf("%lld",&N);
ans=0;
P=log(N+1)/log(2)+1;
//cout<<P<<endl;
for(int p=P;p>=2;p--)
{
//cout<<p<<endl;
long long tmp=binarysearch(p);
if(tmp!=-1)
{
ans=tmp;
break;
}
}
printf("Case #%d: %lld\n",ca,ans);
}
// for(int i=2;i<=N;i++)
// {
// cout<<i<<" "<<calnum(i)<<endl;
// }
return 0;
}
大数据中,二分比较乘积是否相等会有溢出问题。在计算时,只能通过循环相加而不能直接由等比数列求和公式计算。如果之间的某
一位就已经>N了
,就直接返回,因为算到最后第p位时值只会更大。另外,有可能在算到第i位时没有溢出且<N,但是在i+1位时溢出了(如果溢出那么一定是>N)。如果第i位的值,那么在第i+1位时一定>N。这样可以避免overflow。
eg., if and ,那么,而累加到下一位的值是,必然>N。
因为ret是整数,下取整也没有影响。eg.,如果,那么即使和3比较,ret>3说明ret>=4,也一定满足ret>3.25。
大数据代码如下。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
using namespace std;
//2017 RoundE Problem B. Beautiful Numbers
int T;
long long N;
int P;
long long ans;
int calnum(int base)
{
int cnt=0;
int num=N;
while(num>0)
{
int bit=num%base;
num=num/base;
if(bit==1)
{
cnt++;
}
else
{
return -1;
}
}
return cnt;
}
long long power(long long base,int p)
{
long long ret=1;
for(int i=0;i<p;i++)
{
ret*=base;
}
return ret;
}
int fun(long long base,int p)
{
long long val=0;
long long ret=1;
for(int i=0;i<p;i++)
{
if(i!=0)
{
ret*=base;
}
val+=ret;
if(val>N)//val may overflow
{
return 1;
}
// if(i<p-1)//still have one more digit to add
// {
// if((N-val)/base<ret)
// {
// return 1;
// }
// }
if(i<p-1&&ret>N/base)//the above is also ok, ret is integer, then even is N/base is the floor of a decimal number, it is also fine.
{
return 1;
}
}
if(val==N)
{
return 0;
}
else if(val<N)
{
return -1;
}
}
long long binarysearch(int p)
{
long long left=2;
long long right=N;
long long mid=(left+right)/2;
int cnt=0;
while(left<=right)
{
mid=(left+right)/2;
//double tmp=fun(mid,p);
long long tmp=fun(mid,p);
//cout<<left<<" "<<right<<" "<<mid<<" "<<tmp<<endl;
//if(abs(tmp-N)<1e-7)
if(tmp==0)
//if(abs(log(tmp)-log(N)-log(mid-1))<1e-7)
{
return mid;
}
if(tmp==1)
//if(log(tmp)-log(N)-log(mid-1)>0)
{
right=mid-1;
}
else if(tmp==-1)
//else if(log(tmp)-log(N)-log(mid-1)<0)
{
left=mid+1;
}
cnt++;
// if(cnt>10)
// {
// break;
// }
}
return -1;
}
int main()
{
freopen("B-small-practice.in","r",stdin);
//freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
scanf("%lld",&N);
ans=0;
P=log(N+1)/log(2)+1;
//cout<<P<<endl;
for(int p=P;p>=2;p--)
{
//cout<<p<<endl;
long long tmp=binarysearch(p);
if(tmp!=-1)
{
ans=tmp;
break;
}
}
printf("Case #%d: %lld\n",ca,ans);
}
// for(int i=2;i<=N;i++)
// {
// cout<<i<<" "<<calnum(i)<<endl;
// }
return 0;
}