https://www.luogu.org/problemnew/show/P3311
题意都是中文的,相信大家都很清楚
这道题我最开始以为是矩阵快速幂。。。但不过发现第一位不能是零,题目是小于N的,这样好像并不好弄。
既然与数的位数有关就用数位dp吧,其实数位dp我也忘了怎么写。
首先建立AC自动机,然后dp[pos][j]表示第pos位和自动机上j位的匹配数,然后直接枚举相加就可以了,这种做法枚举的是几位数的情况,比如枚举两位数有多少种,一位数有多少种,所以不能从0开始的,所以不需要从0开始枚举,(其实我刚刚也不知道怎么回事,把这个改了就过了)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1510;
struct Aho_Trie
{
int nxt[N][26],fail[N],endd[N];
int l,root;
int newnode()
{
endd[l]=fail[l]=0;
memset(nxt[l],0,sizeof(nxt[l]));
return l++;
}
void init()
{
l=0;
root=newnode();
}
void Insert(char *s)
{
int len=strlen(s);
int u=root;
for(int i=0;i<len;i++)
{
int x=s[i]-'0';
if(!nxt[u][x]) nxt[u][x]=newnode();
u=nxt[u][x];
}
endd[u]=1;
}
void build()
{
queue<int>qu;
for(int i=0;i<10;i++)
if(nxt[root][i]) qu.push(nxt[root][i]);
while(!qu.empty())
{
int u=qu.front();qu.pop();
for(int i=0;i<10;i++)
{
if(nxt[u][i]!=0) fail[nxt[u][i]]=nxt[fail[u]][i],qu.push(nxt[u][i]);
else nxt[u][i]=nxt[fail[u]][i];
}
}
}
}ac;
char s[N],tmp[N];
ll dp[N][N];
int len;
ll dfs(int pos,int x,bool limit)
{
if(ac.endd[x]==1) return 0;
if(pos==len-1) return 1;
if(!limit&&dp[pos][x]!=-1) return dp[pos][x];
ll ret=0;
int up=limit?(s[pos+1]-'0'):9;
for(int i=0;i<=up;i++)
{
ret+=dfs(pos+1,ac.nxt[x][i],limit&&i==up);
ret%=mod;
}
if(!limit) dp[pos][x]=ret;
return ret;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>s;
int n;cin>>n;
ac.init();
for(int i=1;i<=n;i++)
{
cin>>tmp;
ac.Insert(tmp);
}
ac.build();
//ac.nxt[0][0]=0;
memset(dp,-1,sizeof(dp));
len=strlen(s);
ll ans=0;
for(int i=0;i<len;i++)
{
int x=(i==0)?(s[i]-'0'):9;
for(int j=1;j<=x;j++)
{
//if(i==0&&j==0) continue;
ans+=dfs(i,ac.nxt[0][j],i==0&&j==s[0]-'0');
ans%=mod;
}
}
cout<<ans<<endl;
return 0;
}