数数

数数

/*
也就是多一个状态,有没有高位的限制

只有紧贴的地方才有最高位的限制
细节比较多的一个数位dp
首先对于每一个不是从最高位开始的,都需要在最开始的时候加上1,也就是初始化

然后对树上的点进行dp
如果不是紧贴的,由于前面已经有数字了,所以这一位可以任意选择
然后紧贴的要分情况讨论:看这一位是否继续紧贴

最后统计答案就可以了

*/
#include <bits/stdc++.h>
using namespace std;
const int N=1210,M=1510;
const int mod=1e9+7;

void add(int &x,int y) {
    x=(x%mod+y%mod)%mod;
}

int ch[M][10],flag[M],fail[M],tot;
void insert(string s) {
    int p=0;
    for(auto i:s) {
        int v=i-'0';
        if(ch[p][v]==0)ch[p][v]=++tot;
        p=ch[p][v];
    }
    flag[p]=1;
}

void build() {
    queue<int>q;
    for(int i=0;i<10;i++)
        if(ch[0][i])q.push(ch[0][i]);
    while(!q.empty()) {
        int now=q.front();q.pop();
        flag[now]|=flag[fail[now]];
        for(int i=0;i<10;i++) {
            if(ch[now][i]) {
                fail[ch[now][i]]=ch[fail[now]][i];
                q.push(ch[now][i]);
            }
            else ch[now][i]=ch[fail[now]][i];
        }
    }
}

int n,m;
char s[N];
int f[N][M][2];

int solve() {
    for(int i=1;i<s[1]-'0';i++)add(f[1][ch[0][i]][0],1);
    add(f[1][ch[0][s[1]-'0']][1],1);
    for(int i=2;i<=n;i++) {
        for(int j=1;j<10;j++)add(f[i][ch[0][j]][0],1);
        for(int j=0;j<=tot;j++) {
            if(flag[j])continue;
            for(int k=0;k<10;k++)add(f[i][ch[j][k]][0],f[i-1][j][0]);
            for(int k=0;k<s[i]-'0';k++)add(f[i][ch[j][k]][0],f[i-1][j][1]);
            add(f[i][ch[j][s[i]-'0']][1],f[i-1][j][1]);
        }
    }
    int ans=0;
    for(int i=0;i<=tot;i++)
        if(flag[i]==0)add(ans,f[n][i][0]+f[n][i][1]);
    return ans;
}

int main() {
    scanf("%s",s+1);
    n=strlen(s+1);
    cin>>m;
    while(m--) {
        string tmp;cin>>tmp;
        insert(tmp);
    }
    build();
    cout<<solve()<<endl;
    return 0;
}
posted @ 2023-04-16 23:56  basicecho  阅读(33)  评论(0)    收藏  举报