题目描述
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。 给定N和S,计算不大于N的幸运数个数。
输入输出格式
输入格式:
输入的第一行包含整数N。 接下来一行一个整数M,表示S中元素的数量。 接下来M行,每行一个数字串,表示S中的一个元素。
输出格式:
输出一行一个整数,表示答案模109+7的值。
AC自动机+数位DP
怎么解决?
构建Trie图
因为只有在Trie图上才能对答案DP并识别所有的非合法串
DP转移很繁琐
但是还是就那么写
i表示是否顶到上界j为第j位(N)k为第k个节点
特判长度不够的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int mod=1e9+7;
const int N=2e4+100;
char C[N];
char S[N];
struct AC_AuTo{
struct Node{
int vis[10];
int end;
int fail;
}AC[N];
/*int cnt;
inline void Clear(int p){
AC[p].end=0;
AC[p].fail=0;
memset(AC[p].vis,0,sizeof(AC[p].vis));
}
inline void Insert(string S){
int R=S.length();
int now=0;
for(int i=0;i<R;i++){
if(!AC[now].vis[S[i]-'0']){
cnt++;
Clear(cnt);
AC[now].vis[S[i]-'0']=cnt;
}
now=AC[now].vis[S[i]-'0'];
}
AC[now].end=1;
}
inline void GetFail(){
queue<int> Q;
for(int i=0;i<10;i++){
if(AC[0].vis[i]){
AC[AC[0].vis[i]].fail=0;
Q.push(AC[0].vis[i]);
}
}
while(!Q.empty()){
int x=Q.front();
Q.pop();
for(int i=0;i<10;i++){
if(AC[x].vis[i]){
AC[AC[x].vis[i]].fail=AC[AC[x].fail].vis[i];
Q.push(AC[x].vis[i]);
AC[AC[x].vis[i]].end|=AC[AC[AC[x].vis[i]].fail].end;
}
else AC[x].vis[i]=AC[AC[x].fail].vis[i];
}
}
}*/
int cnt;
void Clear(int p){
AC[p].fail=AC[p].end=0;
memset(AC[p].vis,0,sizeof(AC[p].vis));
}
void Insert(char *S){
int now=0;
int len=strlen(S);
for(int i=0;i<len;++i){
if(!AC[now].vis[S[i]-'0']){
AC[now].vis[S[i]-'0']=++cnt;
Clear(cnt);
}
now=AC[now].vis[S[i]-'0'];
}
AC[now].end=1;
}
void GetFail(){
queue<int> Q;
for(int i=0;i<10;++i){
if(AC[0].vis[i]){
AC[AC[0].vis[i]].fail=0;
Q.push(AC[0].vis[i]);
}
}
while(!Q.empty()){
int x=Q.front();
Q.pop();
for(int i=0;i<10;++i){
if(AC[x].vis[i]){
AC[AC[x].vis[i]].fail=AC[AC[x].fail].vis[i];
AC[AC[x].vis[i]].end|=AC[AC[AC[x].fail].vis[i]].end;
Q.push(AC[x].vis[i]);
}
else AC[x].vis[i]=AC[AC[x].fail].vis[i];
}
}
}
int F[2][1300][1600];
int m;
void Build(){
cin>>m;
for(int i=1;i<=m;++i){
cin>>S;
Insert(S);
}
GetFail();
}
void Solve(){
cin>>(C+1);
Build();
int n=strlen(C+1);
for(int i=0;i<n;++i){
for(int j=0;j<=cnt;++j){
if(F[0][i][j]){
int len=C[i+1]-'0';
for(int k=0;k<len;++k){
if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]=(F[1][i+1][AC[j].vis[k]]+F[0][i][j])%mod;
}
if(!AC[AC[j].vis[len]].end)F[0][i+1][AC[j].vis[len]]=(F[0][i+1][AC[j].vis[len]]+F[0][i][j])%mod;
}
if(F[1][i][j]){
for(int k=0;k<=9;++k){
if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]=(F[1][i+1][AC[j].vis[k]]+F[1][i][j])%mod;
}
}
if(!j){
if(!i){
int len=C[i+1]-'0';
for(int k=1;k<len;++k){
if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]+=1;
}
if(!AC[AC[j].vis[len]].end)F[0][i+1][AC[j].vis[len]]+=1;
}
else{
for(int k=1;k<=9;++k){
if(!AC[AC[j].vis[k]].end)F[1][i+1][AC[j].vis[k]]+=1;
}
}
}
}
}
int ans=0;
for(int i=0;i<=cnt;++i){
ans=(ans+F[0][n][i])%mod;
ans=(ans+F[1][n][i])%mod;
}
cout<<ans;
}
}Solution;
int main(){
// freopen("test.in","r",stdin);
Solution.Solve();
}
转载于:https://www.cnblogs.com/Leo-JAM/p/10079131.html