魔法咒语

魔法咒语

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

前 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;
    }
}

猜你喜欢

转载自www.cnblogs.com/yijan/p/bzoj4861.html