BZOJ 3530: [Sdoi2014]数数 AC自动机+dp
思路不难,但是细节还是挺多的,要格外注意一下.
code:
#include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define N 2005 #define ll long long #define mod 1000000007 #define setIO(s) freopen(s".in","r",stdin) using namespace std; queue<int>q; char str[N],S[N]; int n,m,tot,ch[N][10],f[N],dp[N][N][2],tag[N]; void insert() { int i,j,len=strlen(str+1),p=0; for(i=1;i<=len;++i) { if(!ch[p][str[i]-'0']) ch[p][str[i]-'0']=++tot; p=ch[p][str[i]-'0']; } tag[p]=1; } void build() { int i,j; for(i=0;i<10;++i) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()) { int u=q.front();q.pop(); tag[u]|=tag[f[u]]; for(i=0;i<10;++i) { int qr=ch[u][i]; if(!qr) { ch[u][i]=ch[f[u]][i]; continue; } f[qr]=ch[f[u]][i]; q.push(qr); } } } int main() { // setIO("input"); int i,j; scanf("%s%d",S+1,&m); n=strlen(S+1); for(i=1;i<=m;++i) scanf("%s",str+1),insert(); build(); for(i=1;i<S[1]-'0';++i) if(!tag[ch[0][i]]) dp[1][ch[0][i]][0]+=1; if(!tag[ch[0][S[1]-'0']]) dp[1][ch[0][S[1]-'0']][1]=1; for(i=1;i<n;++i) { for(j=1;j<10;++j) if(!tag[ch[0][j]]) dp[i+1][ch[0][j]][0]+=1; for(j=0;j<=tot;++j) { if(tag[j]) continue; if(dp[i][j][0]) { for(int k=0;k<10;++k) { if(tag[ch[j][k]]) continue; (dp[i+1][ch[j][k]][0]+=dp[i][j][0])%=mod; } } if(dp[i][j][1]) { for(int k=0;k<S[i+1]-'0';++k) { if(tag[ch[j][k]]) continue; (dp[i+1][ch[j][k]][0]+=dp[i][j][1]); } } if(tag[ch[j][S[i+1]-'0']]) continue; dp[i+1][ch[j][S[i+1]-'0']][1]|=dp[i][j][1]; } } int ans=0; for(i=0;i<=tot;++i) { if(tag[i]) continue; (ans+=dp[n][i][0])%=mod; (ans+=dp[n][i][1])%=mod; } printf("%d\n",ans); return 0; }