魔法咒语
Posted yijan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了魔法咒语相关的知识,希望对你有一定的参考价值。
魔法咒语
没有一个点到极限数据海星。。。虽然极限数据好像没法做?
前 60% 很套路的 acam dp。$ dp[i][j] $ 表示当前匹配到第 $ i $ 个位置,当前在 ACAM 上 $ j $ 号节点。
后 40% 的数据看起来很矩乘。(其实整个数据范围都挺矩乘的) 由于 $ dp[i][j] $ 只能从 $ dp[i - 1][t] $ 和 $ dp[i - 2][t] $ 转移到,矩阵加速一下就好了。
#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;
}
}
以上是关于魔法咒语的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4861[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP
AC自动机 + 矩阵优化 --- [BJOI2017]魔法咒语