[洛谷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;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/9835946.html