P2425 小红帽的回文数

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;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/10959622.html