【BZOJ】【3530】【SDOI2014】数数
AC自动机/数位DP
orz zyf
好题啊= =同时加深了我对AC自动机(这个应该可以叫Trie图了吧……出边补全!)和数位DP的理解……不过不能自己写出来还真是弱……
1 /************************************************************** 2 Problem: 3530 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:1008 ms 7 Memory:33956 kb 8 ****************************************************************/ 9 10 //BZOJ 3530 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=2015,INF=~0u>>2,MOD=1e9+7; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n,m,cnt=1,a[N]; 32 struct Trie{ 33 int ch[10],fail; 34 bool sign; 35 }T[N*10]; 36 char s[N],s1[N]; 37 void ins(){ 38 scanf("%s",s1); 39 int x=1,y; 40 rep(i,strlen(s1)){ 41 y=s1[i]-'0'; 42 if (!T[x].ch[y]) T[x].ch[y]=++cnt; 43 x=T[x].ch[y]; 44 } 45 T[x].sign=1; 46 } 47 int Q[N]; 48 void make_fail(){ 49 int l=0,r=-1,j; 50 Q[++r]=1; 51 while(l<=r){ 52 int x=Q[l++],y; 53 T[x].sign|=T[T[x].fail].sign; 54 rep(i,10){ 55 j=T[x].fail; 56 while(j && T[j].ch[i]==0) j=T[j].fail; 57 if (T[x].ch[i]){ 58 y=T[x].ch[i]; 59 T[y].fail=j ? T[j].ch[i] : 1; 60 Q[++r]=y; 61 }else T[x].ch[i]=j ? T[j].ch[i] : 1; 62 } 63 } 64 } 65 int f[N][N][2]; 66 int main(){ 67 #ifndef ONLINE_JUDGE 68 freopen("3530.in","r",stdin); 69 freopen("3530.out","w",stdout); 70 #endif 71 scanf("%s",s); 72 n=strlen(s); 73 F(i,1,n) a[i]=s[i-1]-'0'; 74 m=getint(); cnt=1; 75 F(i,0,9) T[1].ch[i]=++cnt; 76 F(i,1,m) ins(); 77 make_fail(); 78 79 F(i,1,a[1]) 80 if(!T[T[1].ch[i]].sign) f[1][T[1].ch[i]][i==a[1]]=1; 81 F(i,1,n-1) F(j,1,cnt){ 82 F(k,0,a[i+1]) if(!T[T[j].ch[k]].sign) 83 (f[i+1][T[j].ch[k]][k==a[i+1]]+=f[i][j][1])%=MOD; 84 rep(k,10) if(!T[T[j].ch[k]].sign) 85 (f[i+1][T[j].ch[k]][0]+=f[i][j][0])%=MOD; 86 } 87 int ans=0; 88 F(i,1,cnt) (ans+=f[n][i][0])%=MOD,(ans+=f[n][i][1])%=MOD; 89 90 memset(f,0,sizeof f); 91 F(i,1,9) if (!T[T[1].ch[i]].sign) f[1][T[1].ch[i]][0]=1; 92 F(i,1,n-2) F(j,1,cnt) 93 rep(k,10) if(!T[T[j].ch[k]].sign) 94 (f[i+1][T[j].ch[k]][0]+=f[i][j][0])%=MOD; 95 F(i,1,n-1) F(j,1,cnt) 96 (ans+=f[i][j][0])%=MOD; 97 printf("%d\n",ans); 98 return 0; 99 }
3530: [Sdoi2014]数数
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 404 Solved: 241
[Submit][Status][Discuss]
Description
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
给定N和S,计算不大于N的幸运数个数。
Input
输入的第一行包含整数N。
接下来一行一个整数M,表示S中元素的数量。
接下来M行,每行一个数字串,表示S中的一个元素。
Output
输出一行一个整数,表示答案模109+7的值。
Sample Input
20
3
2
3
14
3
2
3
14
Sample Output
14
HINT
下表中l表示N的长度,L表示S中所有串长度之和。
1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500