[洛谷P3413]SAC#1 - 萌数
题目大意:求$[l,r](0\leqslant l<r< 10^{1001})$中存在长度至少为$2$的回文串的数字数
题解:数位$DP$,发现如果有回文串,若长度为偶数,一定有两个相同的数字相邻;若长度为奇数,一定有两个相同的数字中间间隔一个数字。所以只需要记录前两个数字就行了。注意判断$l$是否符合条件。
卡点:无
C++ Code:
#include <cstdio> #include <algorithm> #include <cstring> #define maxn 1010 const long long mod = 1e9 + 7; char l[maxn], r[maxn]; int num[maxn], tot; long long f[maxn][11][11][2]; long long calc(int x, int lim, int lead, int lst_2, int lst, int had) { if (!x) return had; long long F = f[x][lst_2][lst][had]; if (!lim && lead && ~F) return F; F = 0; for (int i = lim ? num[x] : 9, op = 1; ~i; i--, op = 0) { F += calc(x - 1, lim && op, lead || i, lst, (lead || i) ? i : 10, had || (i == lst_2) || (i == lst)); } F %= mod; if (!lim && lead) f[x][lst_2][lst][had] = F; return F; } long long solve(char *x) { int len = strlen(x); for (int i = 0; i < len; i++) num[len - i] = x[i] & 15; return calc(len, 1, 0, 10, 10, 0); } long long check(char *x) { int len = strlen(x); for (int i = 1; i < len; i++) if (x[i] == x[i - 1]) return 1; for (int i = 2; i < len; i++) if (x[i] == x[i - 2]) return 1; return 0; } int main() { scanf("%s%s", l, r); memset(f, -1, sizeof f); printf("%lld\n", (solve(r) - solve(l) + mod + check(l)) % mod); return 0; }