迴文數
問題描述
給你一個數 N, 求出最小的 B(B>=2) , 使得 N 在 B 進制下爲迴文數。
輸入
第一行 1 個整數 T, 表示數據組數。 接下來 T 行, 每行一個整數 N。
輸出
輸出 T 行, 每行對應一個答案 B。
樣例
樣例輸入1
3
1
4
21
樣例輸入2
3
5
6
7
樣例輸入3
3
345
5462
345332
樣例輸出1
2
3
2
樣例輸出2
2
5
2
樣例輸出3
22
52
114
數據範圍
30%的數據 T<=10, N<=10^4。
100%的數據 T<=1,000, N<=10^10
懵逼.jpg
題解
讀題
舉個例子
3->二進制11
4->三進制11
1400->39進制 35 35
^ ^ 每一個^表示一位
舉完這些個例子你們差不多就知道題意了
轉進制之後,從最高位往下讀和從最低位往上讀的結果都是一樣的
討論
這道題目沒有任何規律
就是暴力枚舉
但是我們絕對不滿足於暴力地暴力枚舉!
就算是暴力枚舉我們也要有可以裝逼的地方!
於是,在只過了兩個點之後我痛定思痛,看了題解,抄到了以下結論
枚舉進制我們分爲2位,和比兩位多的位數
對於數字N=B*B轉K進制後只有兩位AA的情況
有以下結論
A<K
A*K^1+A*K^0=A*(K+1)=N
所以A*(K+1)=B*B=N
①
B=B
A<K+1
==>A<B
②
K=N/A-1>B
所以對於進制K高於B位的,我們可以通過枚舉A得到
所以對於轉進制後只有兩位的數字,求解方法如下
for(int A=sqrt(N);A;A--)
if(N%A==0)return N/A-1;
那麼以上結論適用於進制大於sqrt(N)的
那麼對於K<=sqrt(B)的,只需要 枚舉+判斷 即可
例如對於N是否可以轉成K進制的迴文數,方法如下
int use[100];
bool check(int N,int K)
{
pos=0;
while(N)use[pos++]=N%K,N/=K;//轉進制
for(int i=0;i<=pos>>1;i++)
if(use[i]!=use[pos-1-i])return 0;//如果從做數起第i位和從右數起第i位不同,那麼就不行
return 1;//否則就可以
}
注意
①對於任何N>1,轉成N-1進制一定可以,且轉換結果一定爲11(1*(N-1)^1+1*(N-1)^0=N)
②無論如何請從K=2枚舉
附上對拍代碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
inline long long input()
{
char c=getchar();long long o;
while(c>57||c<48)c=getchar();
for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;
return o;
}
long long T,x,res[100];
void GET(long long x)
{
long long resA=0;
for(long long i=2;i<=sqrt(x)+1;i++)
{
long long a=x,pos=0,flag=1;
while(a)
res[pos++]=a%i,a/=i;
for(long long a=0;a<=pos+1>>1;a++)
if(res[a]!=res[pos-1-a])flag=0;
if(x%i==0&&x/i-1>i)resA=x/i-1;
if(flag){printf("%lld\n",i);return;}
}
if(resA){printf("%lld\n",resA);return;}
printf("%lld\n",x-1);
}
int main()
{
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
T=input();
for(long long i=1;i<=T;i++)
{
x=input();
if(x==1)printf("2\n");
if(x==2)printf("3\n");
if(x>2)GET(x);
}
}