把所有的模式串构建成一个AC自动机。
定义状态:f[i][u]f[i][u]表示到了第ii位,走到AC自动机上的节点。
「走到AC自动机上的节点uu」的具体含义:节点代表的串是数字串的一个后缀,并且是数字串的所有后缀中能被AC自动机识别(一个串SS能被AC自动机识别意为AC自动机上存在一个节点代表串)的最长后缀。
怎样判断一个状态是否合法(不包含所有的模式串作为子串)呢?可以发现,对于一个状态f[i][u]f[i][u],只需要保证节点uu代表的字符串的所有后缀都不等于任何一个模式串。所以定义,表示节点uu不断地往fail指针走,能否走到一个模式串的末尾。这时候只要满足,那么f[i][u]f[i][u]这个状态就是合法的。
然而由于要求不大于NN,所以加上一维,进行数位DP:
:前ii位小于的前ii位。
:前ii位等于的前ii位。
:前ii位大于的前ii位。
转移即枚举第位的取值xx,下面定的第i+1i+1位的值为yy,为在AC自动机上节点uu通过为的边转移到的节点,分类讨论:
1、x<yx<y时
f[i+1][v][0]+=f[i][u][0]+f[i][u][1]f[i+1][v][0]+=f[i][u][0]+f[i][u][1]
f[i+1][v][2]+=f[i][u][2]f[i+1][v][2]+=f[i][u][2]
2、x>yx>y时
f[i+1][v][2]+=f[i][u][2]+f[i][u][1]f[i+1][v][2]+=f[i][u][2]+f[i][u][1]
f[i+1][v][0]+=f[i][u][0]f[i+1][v][0]+=f[i][u][0]
3、x=yx=y时
f[i+1][v][0]+=f[i][u][0]f[i+1][v][0]+=f[i][u][0]
f[i+1][v][1]+=f[i][u][1]f[i+1][v][1]+=f[i][u][1]
f[i+1][v][2]+=f[i][u][2]f[i+1][v][2]+=f[i][u][2]
(注意第11位不能为)
最后结果:
∑l−1i=1∑u∑2k=0f[i][u][k]+∑u(f[l][u][0]+f[l][u][1])∑i=1l−1∑u∑k=02f[i][u][k]+∑u(f[l][u][0]+f[l][u][1])
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1550, MX = 1e9 + 7;
char s[N], ed[N];
int n, m, l, QAQ, len, que[N], f[N][N][3];
bool orz[N];
struct cyx {
int cnt, nxt, go[10];
void init() {
cnt = nxt = 0;
memset(go, 0, sizeof(go));
}
} T[N];
void ins() {
int i, u = 1; for (i = 1; i <= l; i++) {
int c = ed[i] - '0';
if (!T[u].go[c]) T[T[u].go[c] = ++QAQ].init();
u = T[u].go[c];
}
T[u].cnt++;
}
void buildFail() {
int i, c; for (i = que[len = 1] = 1; i <= len; i++) {
int u = que[i];
for (c = 0; c < 10; c++) {
int v = T[u].go[c]; if (!v) {
T[u].go[c] = T[T[u].nxt].go[c];
continue;
}
int w = T[u].nxt; while (!T[w].go[c]) w = T[w].nxt;
T[v].nxt = T[w].go[c]; que[++len] = v;
orz[v] = (T[v].cnt > 0) || orz[T[v].nxt];
}
}
}
int cx(int i, int j) {
if (i < j) return 0; if (i > j) return 2; return 1;
}
void DP() {
int i, u, c; for (i = 1; i < 10; i++) {
u = T[1].go[i]; if (!orz[u])
f[1][u][cx(i, s[1] - '0')]++;
}
for (i = 1; i < n; i++) for (u = 1; u <= QAQ; u++) if (!orz[u])
for (c = 0; c < 10; c++) {
int v = T[u].go[c], op = cx(c, s[i + 1] - '0');
if (!orz[v]) {
if (op == 0) {
f[i + 1][v][0] = (f[i + 1][v][0] + f[i][u][0]) % MX;
f[i + 1][v][0] = (f[i + 1][v][0] + f[i][u][1]) % MX;
f[i + 1][v][2] = (f[i + 1][v][2] + f[i][u][2]) % MX;
}
else if (op == 2) {
f[i + 1][v][2] = (f[i + 1][v][2] + f[i][u][2]) % MX;
f[i + 1][v][2] = (f[i + 1][v][2] + f[i][u][1]) % MX;
f[i + 1][v][0] = (f[i + 1][v][0] + f[i][u][0]) % MX;
}
else {
f[i + 1][v][1] = (f[i + 1][v][1] + f[i][u][1]) % MX;
f[i + 1][v][0] = (f[i + 1][v][0] + f[i][u][0]) % MX;
f[i + 1][v][2] = (f[i + 1][v][2] + f[i][u][2]) % MX;
}
}
}
}
int main() {
int i, j, ans = 0; scanf("%s", s + 1); n = strlen(s + 1); cin >> m;
T[QAQ = 1].init(); T[0].init(); for (i = 0; i < 10; i++) T[0].go[i] = 1;
for (i = 1; i <= m; i++)
scanf("%s", ed + 1), l = strlen(ed + 1), ins();
buildFail(); DP(); for (i = 1; i < n; i++) for (j = 1; j <= QAQ; j++) {
ans = (ans + f[i][j][0]) % MX; ans = (ans + f[i][j][1]) % MX;
ans = (ans + f[i][j][2]) % MX;
}
for (i = 1; i <= QAQ; i++)
ans = (ans + f[n][i][0]) % MX, ans = (ans + f[n][i][1]) % MX;
cout << ans << endl;
return 0;
}