题解 P6754 【[BalticOI 2013 Day1] Palindrome-Free Numbers】

分析:

这道题看着像是\(\;\text{manacher}\)(马拉车),但其实是数位dp

  • 如果某个数上的某一位与它的上一位相同,则这个数肯定是个回文数
  • 同理,如果某个数上的某一位与它的上上一位相同,则这个数肯定也是个回文数

数位dp时要注意前导0的判断。

时间复杂度大概是 \(O(\log(n)\times10)\)

代码:

#include "cstdio"
#define W 20
#define E 11
#define int long long
namespace IAKIOI {
const signed L = 1 << 20 | 1;
char buffer[L], *S, *TT;
#define getchar() ((S == TT && (TT = (S = buffer) + fread(buffer, 1, L, stdin), S == TT)) ? EOF : *S++)
inline void read(auto &x) {
    x = 0;
    bool f = false;
    char s = getchar();
    while (s < '0' || s > '9') {
        if (s == '-')
            f = true;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = x * 10 + s - '0';
        s = getchar();
    }
    f ? -x : x;
}
inline void write(auto x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
}  // namespace IAKIOI
using namespace IAKIOI;
int pow[W];
inline void getnxt(int &last1, int &last2, int v) {
    if (last1 == 10)
        last1 = v;
    else
        last2 = last1, last1 = v;
}
inline bool judge(int &last1, int &last2, int v) { return v != last1 && v != last2; }
int dp[E][E][W][2];
bool v[E][E][W][2];
inline int work(int last1, int last2, int n, int tmp) {
    if (!n)
        return 1;
    if (v[last1][last2][n][tmp])
        return dp[last1][last2][n][tmp];
    int l1, l2, vis, tot = 0;
    v[last1][last2][n][tmp] = 1;
    for (int i = 0; i <= 9; ++i) {
        vis = (tmp || i) ? 1 : 0;
        l1 = last1;
        l2 = last2;
        if (vis && !judge(l1, l2, i))
            continue;
        if (vis)
            getnxt(l1, l2, i);
        tot += work(l1, l2, n - 1, vis);
    }
    return dp[last1][last2][n][tmp] = tot;
}
inline int solve(int n) {
    int ans = 0, x, last1 = 10, last2 = 10, l1, l2, tmp;
    bool ok = false;
    for (int i = 18; i >= 0; --i)
        if ((x = n / pow[i] % 10) || ok) {
            for (int j = 0; j < x; ++j) {
                tmp = (ok || j) ? 1 : 0;
                l1 = last1, l2 = last2;
                if (tmp && !judge(l1, l2, j))
                    continue;
                if (tmp)
                    getnxt(l1, l2, j);
                ans += work(l1, l2, i, tmp);
            }
            ok = 1;
            if (!judge(last1, last2, x))
                break;
            getnxt(last1, last2, x);
        }
    return ans;
}
signed main() {
    for (int i = pow[0] = 1; i <= 18; ++i) pow[i] = pow[i - 1] * 10;
    int l, r;
    read(l), read(r);
    write(solve(r + 1) - solve(l));
    return 0;
}

posted @ 2020-10-28 19:29  Nakiri_Ayame_suki  阅读(182)  评论(0编辑  收藏  举报