P2425 小红帽的回文数
暴力枚举转换进制这个是人都会。但是只有40pts。
其实有这么个规律:对于\(x\),在\(x+1\)进制下肯定是回文数,之后也是,因为只有一位。所以只需要枚举到\(x+1\)为止。但是没什么用。
我们考虑优化其中一部分进制。
当进制小于\(\sqrt{a_i}\)时,会有很多位,而大于等于\(\sqrt{a_i}\)时只有两位。
两位还回文,那这两位数字都相同。设这个数字为\(j\),进制为\(b\),则有:
\[b \times j + j=a_i\]
可以解出\(b=\frac{a_i}{j}−1\),当\(a_i\)能被\(j\)整除时就有解。
所以当进制小于\(\sqrt{a_i}\)时,复杂度为
\(O(\sqrt{a_i} \log \sqrt{a_i})\),大于等于时为\(O(\sqrt{a_i})\)。
所以能过。
代码:
#include<cstdio>
#include<cmath>
#include<vector>
#define ll long long
const int maxn = 100005;
ll vec[maxn], tot;
ll m;
bool check(ll a, ll b) {
tot = 0;
while(a) {
vec[++tot] = a % b; a /= b;
}
ll i = 1, j = tot;
while(i <= j) {
if(vec[i] != vec[j]) return false;
i++, j--;
}
return true;
}
ll read() {
ll ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0') { if(ch == '-') s = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
return s * ans;
}
int main() {
m = read();
while(m--) {
ll a = read();
ll lim = sqrt(a);
bool flag = false;
for(ll i = 2; i <= std::max(2ll, lim); i++) {
if(check(a, i)) {
printf("%lld\n", i);
flag = true; break;
}
}
if(flag) continue;
for(ll i = a / lim; i; i--) {
if(a % i == 0) {
printf("%lld\n", a / i - 1);
flag = true; break;
}
}
if(flag) continue;
printf("%lld\n", a + 1);
}
return 0;
}