魔法咒语

魔法咒语

没有一个点到极限数据海星。。。虽然极限数据好像没法做?

前 60% 很套路的 acam dp。$dp[i][j]$表示当前匹配到第$i$个位置,当前在 ACAM 上$j$号节点。

后 40% 的数据看起来很矩乘。(其实整个数据范围都挺矩乘的) 由于$dp[i][j]$只能从$dp[i - 1][t]$和$dp[i - 2][t]$转移到,矩阵加速一下就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define MAXN 100026
#define P 1000000007
int n , m , l;

int son[MAXN][26] , fail[MAXN] , num[MAXN] , idx;
void ins( char* ch , int id ) {
int len = strlen( ch ) , cur = 0;
for( int i = 0 ; i < len ; ++ i ) {
int x = ch[i] - 'a';
if( !son[cur][x] ) son[cur][x] = ++ idx;
cur = son[cur][x];
}
num[cur] = 1;
}
void build( ) {
queue<int> Q;
for( int i = 0 ; i < 26 ; ++ i ) if( son[0][i] )
Q.push( son[0][i] );
while( !Q.empty() ) {
int x = Q.front(); Q.pop();
int t = fail[x];
for( int i = 0 ; i < 26 ; ++ i )
if( son[x][i] )
fail[son[x][i]] = son[fail[x]][i] , Q.push( son[x][i] ) , num[son[x][i]] |= ( num[son[fail[x]][i]] );
else
son[x][i] = son[fail[x]][i];
}
}
int dp[106][106] , len[106];
char ch[106][106] , zh[106];

int N;
struct mtrx {
int A[206][206];
} cur , tmp , ans ;
void mul( mtrx& A , mtrx& B) {
memset( tmp.A , 0 , sizeof tmp.A );
for( int i = 0 ; i < N ; ++ i )
for( int k = 0 ; k < N ; ++ k ) if( A.A[i][k] )
for( int j = 0 ; j < N ; ++ j )
( tmp.A[i][j] += 1ll * A.A[i][k] * B.A[k][j] % P ) %= P;
}
void power( int n ) {
for( int i = 0 ; i < N ; ++ i ) ans.A[i][i] = 1;
while( n ) {
if( n & 1 ) mul( ans , cur ) , ans = tmp;
mul( cur , cur ) , cur = tmp , n >>= 1;
}
}

signed main() {
cin >> n >> m >> l;
for( int i = 1 ; i <= n ; ++ i ) scanf("%s",ch[i]) , len[i] = strlen( ch[i] );
for( int i = 1 ; i <= m ; ++ i ) scanf("%s",zh) , ins( zh , i );
build( );
if( l <= 100 ) {
dp[0][0] = 1;
for( int i = 0 ; i < l ; ++ i )
for( int k = 0 ; k <= idx ; ++ k) {
for( int j = 1 ; j <= n ; ++ j ) {
if( i + len[j] > l ) continue;
int t = k;
for( int p = 0 ; p < len[j] ; ++ p )
if( !num[son[t][ch[j][p] - 'a']] ) t = son[t][ch[j][p] - 'a'];
else { t = -1; break; }
if( ~t ) ( dp[i + len[j]][t] += dp[i][k] ) %= P;
}
}
int res = 0;
for( int i = 0 ; i <= idx ; ++ i )
( res += dp[l][i] ) %= P;
cout << res << endl;
} else {
for( int i = idx + 1 ; i <= idx * 2 + 1 ; ++ i ) cur.A[i][i - idx - 1] = 1;
for( int i = 0 ; i <= idx ; ++ i ) {
for( int j = 1 ; j <= n ; ++ j ) {
int t = i;
for( int p = 0 ; p < len[j] ; ++ p )
if( !num[son[t][ch[j][p] - 'a']] ) t = son[t][ch[j][p] - 'a'];
else { t = -1; break; }
if( ~t )
if( len[j] == 1 ) ++ cur.A[i][t];
else ++ cur.A[i][t + idx + 1];
}
}
N = idx * 2 + 2;
// for( int i = 0 ; i < N ; ++ i ) {
// for( int j = 0 ; j < N ; ++ j ) cout << cur.A[i][j] << ' '; puts("");
// }
power( l );
memset( cur.A , 0 , sizeof cur.A );
cur.A[0][0] = 1;
mul( cur , ans );
int res = 0;
for( int i = 0 ; i <= idx ; ++ i ) ( res += tmp.A[0][i] ) %= P;
cout << res << endl;
}
}
文章作者: yijan
文章链接: https://yijan.co/old29/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog