HDU2243 考研路茫茫——单词情结 [AC自动机+矩阵]

  就是POJ2778的加强版,思路是一样的。

  出现过给定的单词的单词数=总单词数-未出现过给定单词的单词数,前者等于26^1+26^2+26^3....26^l,后者等于Mat^1+Mat^2+..Mat^l,这里的Mat是根据能走的字符之间的路径数建立出来的邻接矩阵。两者求出来一减就可以了,对2^64取模可以忽略,直接用unsigned long long做,忽视溢出就等于取模了,注意减法最后结果可能小于0,要加2^64变成正数。

  求a^1+..a^n用一次二分就可以,建议这种二分都写成非递归的,效率比较高而且不会有爆栈的隐患。

  

#include <stdio.h>
#include <string.h>
#define MAXN 31

typedef unsigned long long LL;
LL dmat[MAXN][MAXN];
struct matrix{
    LL mz[MAXN][MAXN];
    int n;
    #define FOR(i) for(int i=0;i<n;i++)
    matrix(int nn,int type):n(nn){
        if(type==0)FOR(i)FOR(j)mz[i][j]=0;
        else if(type==1)FOR(i)FOR(j)mz[i][j]=(i==j?1:0);
        else FOR(i)FOR(j)mz[i][j]=dmat[i][j];
    }
    matrix operator *(const matrix& b)const{
        matrix ans(n,0);
        FOR(i)FOR(j)if(mz[i][j])
            FOR(k)ans.mz[i][k]+=mz[i][j]*b.mz[j][k];
        return ans;
    }
    matrix operator +(const matrix& b)const{
        matrix ans(n,0);
        FOR(i)FOR(j)ans.mz[i][j]=mz[i][j]+b.mz[i][j];
        return ans;
    }
    //M^1+M^2+M^3...M^N
    matrix binPlusMul(int x){
        matrix ans(n,0),tmp(n,2),mat(n,2);
        int bit=1;
        for(LL i=(x>>1);i;i>>=1,bit<<=1);bit>>=1;
        for(ans=mat;bit;bit>>=1){
            ans=ans+tmp*ans;
            tmp=tmp*tmp;
            if(bit&x){
                tmp=tmp*mat;
                ans=ans+tmp;
            }
        }
        return ans;
    }
};
int next[MAXN][26],fail[MAXN],flag[MAXN],pos;
int newnode(){
    for(int i=0;i<26;i++)next[pos][i]=0;
    fail[pos]=flag[pos]=0;
    return pos++;
}
void insert(char *s){
    int p=0;
    for(int i=0;s[i];i++){
        int k=s[i]-'a',&x=next[p][k];
        p=x?x:x=newnode();
    }
    flag[p]=1;
}
int q[MAXN],front,rear;
void makenext(){
    q[front=rear=0]=0,rear++;
    while(front<rear){
        int u=q[front++];
        for(int i=0;i<26;i++){
            int v=next[u][i];
            if(flag[v])continue;
            if(v==0)next[u][i]=next[fail[u]][i];
            else q[rear++]=v;

            if(u&&v){
                fail[v]=next[fail[u]][i];
                if(flag[fail[v]])flag[v]=1;
            }
        }
    }
}
LL cal(int x,int n){
    int bit=1;
    LL ans=0,tmp=x;
    for(int i=(n>>1);i;i>>=1,bit<<=1);bit>>=1;
    for(ans=x;bit;bit>>=1){
        ans=ans+tmp*ans;
        tmp=tmp*tmp;
        if(bit&n){
            tmp=tmp*x;
            ans=ans+tmp;
        }
    }
    return ans;

}
int n;
LL l;
char s[10];
int main(){
    //freopen("test.in","r",stdin);
    while(scanf("%d%d",&n,&l)!=EOF){
        pos=0;newnode();
        memset(dmat,0,sizeof dmat);
        for(int i=0;i<n;i++){
            scanf("%s",s);
            insert(s);
        }
        makenext();
        for(int u=0;u<pos;u++){
            if(flag[u])continue;
            for(int i=0;i<26;i++){
                int v=next[u][i];
                if(flag[v])continue;
                dmat[u][v]++;
            }
        }
        matrix mt(pos,2);
        matrix mat=mt.binPlusMul(l);
        LL ans=cal(26,l);
        for(int i=0;i<pos;i++)ans-=mat.mz[0][i];
        if(ans<0)ans+=((LL)1<<63)+((LL)1<<63);
        printf("%I64u\n",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/swm8023/p/2626194.html