【题目链接】
【题意】
给出长度为m,n个模式串,请问只要长度为m的串中有一个模式串就算是可读。
【分析】
其实如果直接分析全部可读的情况,一个串,两个串,……n个串可读。
明显是很复杂而且是做不出来的。
正难则反,其实我们可以需要通过一个(所有可能-全部不可读的情况)不就是答案的方案吗?
记录不合法的方案,考虑dp[i][j] ,下标为j,长度为i 的不可读的情况。
其实不可读的情况就是不经过结尾的结点即可。
最后答案就是利用26个字母,然后子节点通过父节点来累加答案。
最后把对立事件算出来即可。

1 #include<cstdio>
2 #include<cstring>
3 #include<iostream>
4 #include<algorithm>
5
6 using namespace std;
7 const int N = 10005;
8 const int M = 2e6+10;
9 const int mod = 10007;
10 int Trie[M][26] , fail[M] , End[M], idx ;
11 int Q[M] , Head , Tail ;
12 int f[N][N];
13 int n ,m ;
14
15 char str[N];
16
17 void Insert( char s[] ){
18 int p = 0;
19 for(int i=0 ; s[i] ; i++ ){
20 int t = s[i] - 'A' ;
21 if( !Trie[p][t] )
22 Trie[p][t] = ++idx ;
23 p = Trie[p][t];
24 }
25 End[p] |= 1 ;
26 }
27
28 void Build(){
29 Head = 1 , Tail = 0 ;
30 for(int i=0;i<26;i++)
31 if(Trie[0][i])
32 Q[++Tail] = Trie[0][i] ;
33
34 while( Head <= Tail ){
35 int u = Q[Head++] ;
36 for(int i=0;i<26;i++){
37 int To = Trie[u][i];
38 if( To ){
39 fail[To] = Trie[fail[u]][i];
40 Q[++Tail] = To;
41
42 End[To] |= End[fail[To]] ;
43 }else{
44 Trie[u][i] = Trie[fail[u]][i];
45 }
46 }
47 }
48
49 }
50
51 void Solve(){
52 f[0][0] = 1 ;
53 for(int i=1;i<=m;i++){
54 for(int j=0;j<=idx;j++){
55 for(int k=0;k<26;k++){
56 int To = Trie[j][k];
57 if( !End[To] ){
58 (f[i][To] += f[i-1][j]) %= mod ;
59 }
60 }
61 }
62 }
63 int tot = 0 ;
64 for(int i=0;i<=idx;i++){
65 tot = (tot+f[m][i]) % mod ;
66 }
67 int sum = 1 ;
68 for(int i=1;i<=m;i++){
69 sum = sum * 26 % mod ;
70 }
71 printf("%d\n",(sum-tot+mod)%mod );
72 }
73 int main()
74 {
75 ios_base :: sync_with_stdio(false);
76 cin.tie(0) , cout.tie(0);
77 cin >> n >> m ;
78 for(int i=0;i<n;i++){
79 cin >> str ;
80 Insert(str);
81 }
82 Build();
83 Solve();
84 return 0 ;
85 }
