[bzoj3530][Sdoi2014]数数【AC自动机】【数位DP】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=3530
【题解】
  把所有数字串S建立AC自动机,在自动机上DP即可,注意数字串可以有前导零,但你的数不行。
  时间复杂度 O(lL10) O ( l ∗ L ∗ 10 )
【代码】

# include 
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       2010
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Node{
    int son[10], tag;
}T[N];
int nex[N], f[N][N][2][2], q[N], n, m, place;
char s[N], tmp[N];
const int P = 1e9 + 7;
void extend(char *tmp, int l){
    int p = 0;
    for (int i = 1; i <= l; i++){
        if (T[p].son[tmp[i] - '0'] == 0)
            T[p].son[tmp[i] - '0'] = ++place;
        p = T[p].son[tmp[i] - '0'];
    }
    T[p].tag = true;
}
void buildfail(){
    int pl = 1, pr = 1; q[1] = 0;
    while (pl <= pr){
        int x = q[pl++];
        for (int i = 0; i <= 9; i++)
            if (T[x].son[i] != 0){
                int p = x;
                while (p != 0 && T[nex[p]].son[i] == 0) 
                    p = nex[p];
                if (x == 0) nex[T[x].son[i]] = 0;
                    else {
                        nex[T[x].son[i]] = T[nex[p]].son[i];
                        if (T[T[nex[p]].son[i]].tag == true)
                            T[T[x].son[i]].tag = true;
                    }
                q[++pr] = T[x].son[i];
            }
    }
}
int solve(){
    for (int i = 0; i <= n - 1; i++){
        for (int j = 0; j <= place; j++){
            if (T[j].tag) continue;
            for (int k = 1; k <= 9; k++){
                int p = j;
                while (p != 0 && T[p].son[k] == 0) p = nex[p];
                p = T[p].son[k];
                if (T[p].tag) continue;
                if (s[i + 1] > k)
                    f[i + 1][p][1][0] = (1ll * f[i + 1][p][1][0] + f[i][j][0][0] + f[i][j][0][1]) % P;
                if (s[i + 1] == k){
                    f[i + 1][p][1][0] = (f[i + 1][p][1][0] + f[i][j][0][0]) % P;
                    f[i + 1][p][1][1] = (f[i + 1][p][1][1] + f[i][j][0][1]) % P;        
                }
                if (s[i + 1] < k)
                    f[i + 1][p][1][0] = (f[i + 1][p][1][0] + f[i][j][0][0]) % P;
            }
            if (s[i + 1] > 0)
                f[i + 1][0][0][0] = f[i][0][0][0] + f[i][0][0][1];
                else {
                    f[i + 1][0][0][1] = f[i][0][0][1];
                    f[i + 1][0][0][0] = f[i][0][0][0];
                }
            for (int k = 0; k <= 9; k++){
                int p = j;
                while (p != 0 && T[p].son[k] == 0) p = nex[p];
                p = T[p].son[k];
                if (T[p].tag) continue;
                if (s[i + 1] > k)
                    f[i + 1][p][1][0] = (1ll * f[i + 1][p][1][0] + f[i][j][1][0] + f[i][j][1][1]) % P;
                if (s[i + 1] == k){
                    f[i + 1][p][1][0] = (f[i + 1][p][1][0] + f[i][j][1][0]) % P;
                    f[i + 1][p][1][1] = (f[i + 1][p][1][1] + f[i][j][1][1]) % P;        
                }
                if (s[i + 1] < k)
                    f[i + 1][p][1][0] = (f[i + 1][p][1][0] + f[i][j][1][0]) % P;
            }
        }
    }
    int ans = 0;
    for (int i = 0; i <= place; i++)
        if (!T[i].tag)
            ans = (1ll * ans + f[n][i][1][0] + f[n][i][1][1]) % P;
    return ans;
}
int main(){
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
    scanf("\n%s", s + 1);
    n = strlen(s + 1);
    for (int i = 1; i <= n; i++)
        s[i] = s[i] - '0';
    m = read();
    for (int i = 1; i <= m; i++){
        scanf("\n%s", tmp + 1);
        int l = strlen(tmp + 1);
        extend(tmp, l);
    }
    buildfail();
    f[0][0][0][1] = 1;
    printf("%d\n", solve());
    return 0;
}

你可能感兴趣的:(【ac自动机】,【数位dp】)