HDU-2243 考研路茫茫——单词情结 AC自动机+矩阵快速幂

题意

给n个模式串,问有多少个长度不超过L的字符串中至少出现一种模式串。

分析

有多少个长度为L的字符串中不出现任意一个模式串的题已经做过,构造一个矩阵\(A\),答案\(s_n\)即为\(s_0*A^n\)

用矩阵快速幂算下就行了,这题的计算方法就显然是\(26^0+26^1+26^2+\dots+26^n-(s_0*A^0+s_0*A^1+s_0*A^2+\dots+s_0*A^n)\)

这样显然会超时,考虑重新构造两个矩阵
\[ \left [ \begin{matrix}26^n&s_n\end{matrix}\right ] \times \left [ \begin{matrix}26&1\\0&1\end{matrix}\right ] =\left [ \begin{matrix}26^{n+1}&s_{n+1}\end{matrix}\right ] \]
设字典树一共\(m\)个结点,我们要构造一个\((m+1)\times(m+1)\)的矩阵
\[ \left [ \begin{matrix}f[n][0]&\dots&f[n][m-1]&s_n\end{matrix}\right ] \times \left [ \begin{matrix}A&1\\0&1\end{matrix}\right ] =\left [ \begin{matrix}f[n+1][0]&\dots&f[n+1][m-1]&s_{n+1}\end{matrix}\right ] \]
对于取模,直接用ull自然溢出就行了。

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll unsigned long long
using namespace std;
const int inf=1e9;
const ll mod=1e9+7;
const int maxn=1e5+10;
int n;
ll L;
char s[11];
struct mat{
    int n;
    ll a[40][40];
    mat(){
        memset(a,0,sizeof(a));
    }
    mat(int _n){
        n=_n;memset(a,0,sizeof(a));
    }
    mat operator *(const mat &r)const{
        mat ret=mat(n);
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        for(int k=0;k<n;k++)
        ret.a[i][j]+=a[i][k]*r.a[k][j];
        return ret;
    }
};
mat A,B=mat(2);
mat ksm(mat a,ll b){
    mat ret=mat(a.n);
    for(int i=0;i<ret.n;i++) ret.a[i][i]=1;
    while(b){
        if(b&1) ret=ret*a;
        b>>=1;
        a=a*a;
    }
    return ret;
}
struct ACtree{
    int son[maxn][26],fail[maxn],ed[maxn],tot;
    int newnode(){
        for(int i=0;i<26;i++) son[tot][i]=0;
        ed[tot++]=0;
        return tot-1;
    }
    void init(){
        tot=0;newnode();
    }
    void ins(char s[]){
        int rt=0,m=strlen(s);
        for(int i=0;i<m;i++){
            if(!son[rt][s[i]-'a']) son[rt][s[i]-'a']=newnode();
            rt=son[rt][s[i]-'a'];
        }
        ed[rt]=1;
    }
    void gao(){
        queue<int>q;
        for(int i=0;i<26;i++) if(son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(son[u][i]){
                    fail[son[u][i]]=son[fail[u]][i];
                    q.push(son[u][i]);
                }else{
                    son[u][i]=son[fail[u]][i];
                }
                ed[son[u][i]]|=ed[fail[son[u][i]]];
            }
        }
        A=mat(tot+1);
        for(int i=0;i<tot;i++){
            for(int j=0;j<26;j++){
                if(ed[son[i][j]]) continue;
                A.a[i][son[i][j]]++;
            }
        }
        for(int i=0;i<=tot;i++) A.a[i][tot]=1;
    }
    ll qy(){
        ll ans=0;
        mat ret=ksm(B,L);
        ans+=ret.a[0][1]+ret.a[0][0];
        ret=ksm(A,L);
        for(int i=0;i<=tot;i++) ans-=ret.a[0][i];
        return ans;
    }
}AC;
int main(){
    //ios::sync_with_stdio(false);
    //freopen("in","r",stdin);
    B.a[0][0]=26,B.a[0][1]=B.a[1][1]=1;
    while(~scanf("%d%llu",&n,&L)){
        AC.init();
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            AC.ins(s);
        }
        AC.gao();
        printf("%llu\n",AC.qy());
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xyq0220/p/11593462.html