魔法咒语

魔法咒语

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

前 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;
	}
}
posted @ 2020-01-18 11:50  yijan  阅读(284)  评论(0编辑  收藏  举报