1.题目
题目描述
我的生日快到了!唉,但如今我已经老了,我想重新获得年轻的感觉。
幸运的是,我想出了一个让人感觉更年轻的好方法:如果我把我的年龄以适当选择的
b
b
b进制书写,那么它看起来会更小。例如,假设我以
10
10
10进制书写的年龄是
32
32
32岁;以
16
16
16进制书写,它只有
20
20
20(
0
x
20
0x20
0x20)!
然而,在这样做时,我不能选择任意进制数。如果以
b
b
b进制为数写的我的年龄包含
0
−
9
0-9
0−9以外的数字,那么很明显我在作弊,这违背了目的。此外,如果我的年龄的进制数
b
b
b太小,那么很明显我在作弊。
在我希望我的年龄看起来有多小的问题上,考虑到我的年龄
y
y
y和下限
l
l
l,找到最大的进制数
b
b
b,这样写在基数
b
b
b中的
y
y
y只包含十进制数字,并且当将其看做一个十进制数字时至少是
l
l
l。
输入格式
输入由一行组成,其中包含两个 10 10 10进制的整数 y y y ( 10 ≤ y ≤ 1 0 18 10\le y\le10^{18} 10≤y≤1018 –是的,我很老)和 l l l( 10 ≤ l ≤ y 10\le l \le y 10≤l≤y)
输出格式
如上所述,输出最大进制数 b b b。
说明/提示
时间限制: 1 s 1s 1s,内存限制: 1 G B 1GB 1GB
样例输入 #1
32 20
样例输出 #1
16
样例输入 #2
2016 100
样例输出 #2
42
2.思路
我们考虑枚举y转成b进制时的那个数(记为
x
x
x)。
首先考虑到
x
x
x 不用枚举太多,因为当
x
x
x 太大时,
b
b
b 会很小,那时只需要枚举
b
b
b 就行了。
经过本人的多次测试:
x
x
x 只要枚举到
1000
1000
1000 ,剩下到靠枚举
b
b
b 即可。
接下来我们考虑枚举
x
x
x 怎么做:
①:
x
x
x 是一个两位数,设它是
a
1
×
10
+
b
1
a_1\times 10+b_1
a1×10+b1,则我们可以解一个一元一次方程:
a
1
⋅
b
+
a
2
=
x
a_1\cdot b+a_2=x
a1⋅b+a2=x,可以轻松解出
b
b
b。
②:
x
x
x 是一个三位数,设它是
a
1
×
1
0
2
+
a
2
×
10
+
a
3
a_1\times 10^2+a_2\times 10+a_3
a1×102+a2×10+a3,则我们可以解一个一元三次方程:
a
1
∗
b
2
+
a
2
∗
b
+
a
3
=
x
a_1*b^2+a_2*b+a_3=x
a1∗b2+a2∗b+a3=x,即
a
1
∗
b
2
+
a
2
∗
b
+
(
a
3
−
x
)
=
0
a_1*b^2+a_2*b+(a_3-x)=0
a1∗b2+a2∗b+(a3−x)=0,利用求根公式
b
=
−
b
±
b
2
−
4
⋅
a
⋅
c
2
⋅
a
b=\frac{-b±\sqrt{b^2-4\cdot a\cdot c}}{2\cdot a}
b=2⋅a−b±b2−4⋅a⋅c,可以快速求出根,但是注意要使用__int128
或 long double
。
这样枚举
x
x
x 就完成了。
接下来考虑枚举
b
b
b 怎么做:
将
b
b
b 从 1e6
开始往下枚举,每次都将
y
y
y 转换成
b
b
b 进制,然后判断是否有一位大于
9
9
9,最后再和
l
l
l 比较一下即可。
3.代码
1.解一元一次方程部分
for(register int i=max(l,10ll);i<=99;++i){
int a=i/10,b=i%10;//找ap+b=y
if((y-b)%a==0){
ans=max(ans,(y-b)/a);
}
}
2.解一元二次方程部分
for(register int i=max(l,100ll);i<=999;++i){
Int a=i/100,b=i/10%10,c=i%10-y;//求a*p^2+b*p+c=0
Int nick=b*b-4*a*c;
if(nick<0)
continue;
nick=Sqrt(nick);
Int p1=-b+nick,p2=-b-nick;
p1=p1/(2*a),p2=p2/(2*a);
for(int pp=1;pp<=2;pp++)
{
Int L=p1-20,R=p1+20;
if(L<10)
L=10;
for(Int xp=L;xp<=R;++xp){
Int sum=a*xp*xp+b*xp+c;
if(sum==0){
if(xp>ans)
ans=xp;
break;
}
}
swap(p1,p2);
}
}
其中Int
表示__int128
3.暴力枚举部分
for(register int i=1e6;i>=10;--i){
if(i<ans){
break;
}
zhuan(i);
if(!check())
continue;
if(cmp()){
ans=max(ans,i);
break;
}
}
4.其余函数部分
inline void zhuan(int x){
cct=0;
int p=y;
while(p){
cc[++cct]=p%x;
p/=x;
}
for(register int i=1;i<=cct/2;++i)
swap(cc[i],cc[cct-i+1]);
return;
}
inline bool check(){
for(register int i=1;i<=cct;++i){
if(cc[i]>9)
return false;
}
return true;
}
inline bool cmp(){
int ans=0;
for(register int i=1;i<=cct;++i)
ans=ans*10+cc[i];
if(ans>=l)
return true;
else
return false;
}
Int Read(){
Int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
void print(Int x){
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar(x%10+'0');
}
Int Sqrt(Int x){
Int L=1,R=1000000000000000;
while(L<R){
Int mid=L+R;
mid=mid/2;
if(mid*mid<x){
L=mid+1;
}
else{
R=mid;
}
}
for(Int i=L-5;i<=L+5;++i){
if(i*i<=x&&(i+1)*(i+1)>x){
return i;
}
}
return -1;
}
5.完整代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Int __int128
#define doudle long double
inline int read();
int y,l;
int cc[1377];
int cct;
int ans;
inline void zhuan(int x){
cct=0;
int p=y;
while(p){
cc[++cct]=p%x;
p/=x;
}
for(register int i=1;i<=cct/2;++i)
swap(cc[i],cc[cct-i+1]);
return;
}
inline bool check(){
for(register int i=1;i<=cct;++i){
if(cc[i]>9)
return false;
}
return true;
}
inline bool cmp(){
int ans=0;
for(register int i=1;i<=cct;++i)
ans=ans*10+cc[i];
if(ans>=l)
return true;
else
return false;
}
Int Read(){
Int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
void print(Int x){
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar(x%10+'0');
}
Int Sqrt(Int x){
Int L=1,R=1000000000000000;
while(L<R){
Int mid=L+R;
mid=mid/2;
if(mid*mid<x){
L=mid+1;
}
else{
R=mid;
}
}
for(Int i=L-5;i<=L+5;++i){
if(i*i<=x&&(i+1)*(i+1)>x){
return i;
}
}
return -1;
}
signed main(){
y=read(),l=read();
for(register int i=max(l,10ll);i<=99;++i){
int a=i/10,b=i%10;//找ap+b=y
if((y-b)%a==0){
ans=max(ans,(y-b)/a);
}
}
for(register int i=max(l,100ll);i<=999;++i){
Int a=i/100,b=i/10%10,c=i%10-y;//求a*p^2+b*p+c=0
Int nick=b*b-4*a*c;
if(nick<0)
continue;
nick=Sqrt(nick);
Int p1=-b+nick,p2=-b-nick;
p1=p1/(2*a),p2=p2/(2*a);
for(int pp=1;pp<=2;pp++)
{
Int L=p1-20,R=p1+20;
if(L<10)
L=10;
for(Int xp=L;xp<=R;++xp){
Int sum=a*xp*xp+b*xp+c;
if(sum==0){
if(xp>ans)
ans=xp;
break;
}
}
swap(p1,p2);
}
}
for(register int i=1e6;i>=10;--i){
if(i<ans){
break;
}
zhuan(i);
if(!check())
continue;
if(cmp()){
ans=max(ans,i);
break;
}
}
printf("%llu\n",ans);
return 0;
}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}