数数

数数

/*
也就是多一个状态,有没有高位的限制
只有紧贴的地方才有最高位的限制
细节比较多的一个数位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 @   basicecho  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示