Time Limit: 10 Sec Memory Limit: 512 MB
Description
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。给定N和S,计算不大于N的幸运数个数。
Input
输入的第一行包含整数N。
接下来一行一个整数M,表示S中元素的数量。
接下来M行,每行一个数字串,表示S中的一个元素。
Output
输出一行一个整数,表示答案模 109+7 的值。
Sample Input
20
3
2
3
14
Sample Output
14
HINT
下表中l表示N的长度,L表示S中所有串长度之和。
1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500
【原题地址】
【分析】AC自动机 + DP
先用
AC
自动机对
S
集合的字符串建立
然后我们记
f[i][j][k]
表示当前已经确定到第
i
位数,走到
对于状态
k
,我们有如下定义:
[1].
[2].
[3].
接下来我们考虑如何转移:枚举第
[1]. 若
f[i+1][x][0]+=f[i][j][0]+f[i][j][1]
f[i+1][x][2]+=f[i][j][2]
[2]. 若
num
等于
N
的第
f[i+1][x][0]+=f[i][j][0]
f[i+1][x][1]+=f[i][j][1]
f[i+1][x][2]+=f[i][j][2]
[3]. 若
num
大于
N
的第
f[i+1][x][0]+=f[i][j][0]
f[i+1][x][2]+=f[i][j][2]+f[i][j][1]
每确定一位数都要将
∑(f[i+1][x][0]+f[i+1][x][1]+f[i+1][x][2])
累加进答案
Ans
,同时因为幸运数不能大于
N
,所以最终的答案还要减去
【代码】
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int Maxn = 0x3f3f3f3f;
const int N = 1505, M = 1205;
const ll Mod = 1e9 + 7;
ll f[M][N][3], Ans;
bool pos[N]; char s[M], a[N];
int n, m, T, G[N][10], Q[N], nxt[N], lst[N];
inline int get()
{
char ch; bool f = false; int res = 0;
while (((ch = getchar()) < '0' || ch > '9') && ch != '-');
if (ch == '-') f = true;
else res = ch - '0';
while ((ch = getchar()) >='0' && ch <= '9')
res = (res << 3) + (res << 1) + ch - '0';
return f? ~res + 1 : res;
}
inline void put(int x)
{
if (x < 0)
x = ~x + 1, putchar('-');
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}
inline void Insert()
{
scanf("%s", a + 1);
int x = 0, l = strlen(a + 1);
for (int i = 1; i <= l; ++i)
{
int y = a[i] - '0';
if (!G[x][y]) G[x][y] = ++T;
x = G[x][y];
}
pos[x] = true;
}
inline void Bfs()
{
int t, w, x, y; t = w = 0;
for (int i = 0; i < 10; ++i)
if (G[0][i]) Q[++w] = G[0][i];
while (t < w)
{
x = Q[++t];
for (int i = 0; i < 10; ++i)
if (!G[x][i]) G[x][i] = G[nxt[x]][i];
else
{
Q[++w] = y = G[x][i]; int v = nxt[x];
while (!G[v][i] && v) v = nxt[v];
nxt[y] = G[v][i];
lst[y] = pos[nxt[y]] ? nxt[y] : lst[nxt[y]];
}
}
}
inline int cmp(const int &x, const int &y)
{
if (x > y) return 2;
if (x < y) return 0;
return 1;
}
int main()
{
scanf("%s", s + 1);
n = strlen(s + 1); m = get();
while (m--) Insert(); Bfs();
for (int i = 1; i < 10; ++i) //不含前导0
{
int x = G[0][i];
if (!pos[x] && !lst[x]) f[1][x][cmp(i, s[1] - '0')]++;
}
for (int i = 0; i <= T; ++i)
(Ans += f[1][i][0] + f[1][i][1] + f[1][i][2]) %= Mod;
for (int i = 1; i < n; ++i)
{
for (int j = 0; j <= T; ++j)
if (f[i][j][0] || f[i][j][1] || f[i][j][2])
for (int k = 0; k < 10; ++k)
{
int x = j;
while (!G[x][k] && x) x = nxt[x];
x = G[x][k];
if (pos[x] || lst[x]) continue;
int v = cmp(k, s[i + 1] - '0');
switch (v)
{
case 0:
(f[i + 1][x][0] += f[i][j][0] + f[i][j][1]) %= Mod;
(f[i + 1][x][2] += f[i][j][2]) %= Mod; break;
case 1:
(f[i + 1][x][0] += f[i][j][0]) %= Mod;
(f[i + 1][x][1] += f[i][j][1]) %= Mod;
(f[i + 1][x][2] += f[i][j][2]) %= Mod; break;
case 2:
(f[i + 1][x][2] += f[i][j][2] + f[i][j][1]) %= Mod;
(f[i + 1][x][0] += f[i][j][0]) %= Mod; break;
}
}
for (int j = 0; j <= T; ++j)
{
(Ans += f[i + 1][j][0] + f[i + 1][j][1]) %= Mod;
if (i + 1 < n) (Ans += f[i + 1][j][2]) %= Mod;
}
}
return put(Ans), 0;
}