power oj 2790: GAUSS 2014(AC自动机fail数组运用+矩阵快速幂)

DNA Sequence POJ - 2778的弱化版.
只有一个模式串,因此不用建fail数组。直接建前缀树进行匹配即可。
需要建fail数组,不然会被下面这组数据hack。

100
acacab

为什么要建fail数组呢?实际上还有个目的。当我们pos=5时,会查找是否可以继续走下去。如果没有fail数组,我们就一步走不到pos=4。当我们有了fail数组,才可以让他继续从pos=4这个点继续匹配。所以必须要有pos数组。


错误代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
//#pragma GCC optimize(3,"Ofast","inline")
#define LL long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=1e9+7;
const int maxn=2e6+10;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
struct node{
    LL mat[150][150];
}M[5];
char t[25];
int trie[500][30],vis[500],tot;
char dir[200];
void add_trie(char *str){
    int len=strlen(str);
    int pos=0;
    for (int i=0;i<len;i++){
        if (!trie[pos][str[i]-'a']) trie[pos][str[i]-'a']=++tot;
        pos=trie[pos][str[i]-'a'];
    }
    vis[pos]++;
}
void build_trie(int n){
    MT(trie,0);
    MT(vis,0);
    tot=0;
    for (int i=0;i<n;i++){
        scanf("%s",t);
        add_trie(t);
        vis[strlen(t)]=1;
    }
    for (int i=0;i<=tot;i++){
        if (vis[i]) continue;
        for (int k=0;k<26;k++){
            if (trie[i][k]){
                if (!vis[trie[i][k]])
                    M[0].mat[i][trie[i][k]]++;
            } else {
                if (trie[0][k]) M[0].mat[i][trie[0][k]]++;
                else M[0].mat[i][0]++;
            }
        }
    }
}
void mat_mul(int a,int b,int d){
    node tmp = node();
    for (int i=0;i<=tot;i++){
        for (int j=0;j<=tot;j++){
            for (int k=0;k<=tot;k++){
                tmp.mat[i][j]+=M[a].mat[i][k]*M[b].mat[k][j];
                tmp.mat[i][j]%=mod;
            }
        }
    }
    M[d]=tmp;
}
void mat_qpow(int n,int p){
    for (int i=0;i<=tot;i++){
        M[1].mat[i][i]=1;
    }
    while (p){
        if (p&1){
            mat_mul(n,1,1);
        }
        p>>=1;
        mat_mul(n,n,n);
    }
}
int main(){
    int n,L;
    while (~scanf("%d",&L)){
        n=1;
        MT(M[0].mat,0);
        MT(M[1].mat,0);
        build_trie(n);
        int ans=0;
        mat_qpow(0,L);
        for (int i=0;i<=tot;i++){
            ans+=M[1].mat[0][i];
            ans=ans%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

真正的AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
//#pragma GCC optimize(3,"Ofast","inline")
#define LL long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=1e9+7;
const int maxn=2e6+10;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
struct node{
    LL mat[150][150];
}M[5];
char t[25];
int trie[500][30],vis[500],fail[maxn],tot;
char dir[200];
void add_trie(char *str){
    int len=strlen(str);
    int pos=0;
    for (int i=0;i<len;i++){
        if (!trie[pos][str[i]-'a']) trie[pos][str[i]-'a']=++tot;
        pos=trie[pos][str[i]-'a'];
    }
    vis[pos]++;
}
void get_fail(){
    queue<int>q;
    for (int i=0;i<26;i++){
        if (trie[0][i]){
            q.push(trie[0][i]);
            fail[trie[0][i]]=0;
        }
    }
    while (!q.empty()){
        int pos=q.front();
        q.pop();
        for (int i=0;i<26;i++){
            if (trie[pos][i]){
                q.push(trie[pos][i]);
                fail[trie[pos][i]]=trie[fail[pos]][i];
            } else trie[pos][i]=trie[fail[pos]][i];
        }
    }
}
void build_trie(int n){
    MT(trie,0);
    MT(vis,0);
    MT(fail,0);
    tot=0;
    for (int i=0;i<n;i++){
        scanf("%s",t);
        add_trie(t);
        vis[strlen(t)]=1;
    }
    get_fail();
    for (int i=0;i<=tot;i++){
        if (vis[i]) continue;
        for (int k=0;k<26;k++){
            if (vis[trie[i][k]]) continue;
            if (trie[i][k]){
                    M[0].mat[i][trie[i][k]]++;
            } else M[0].mat[i][trie[fail[i]][k]]++;
        }
    }
}
void mat_mul(int a,int b,int d){
    node tmp = node();
    for (int i=0;i<=tot;i++){
        for (int j=0;j<=tot;j++){
            for (int k=0;k<=tot;k++){
                tmp.mat[i][j]+=M[a].mat[i][k]*M[b].mat[k][j];
                tmp.mat[i][j]%=mod;
            }
        }
    }
    M[d]=tmp;
}
void mat_qpow(int n,int p){
    for (int i=0;i<=tot;i++){
        M[1].mat[i][i]=1;
    }
    while (p){
        if (p&1){
            mat_mul(n,1,1);
        }
        p>>=1;
        mat_mul(n,n,n);
    }
}
int main(){
    int n,L;
    while (~scanf("%d",&L)){
        n=1;
        MT(M[0].mat,0);
        MT(M[1].mat,0);
        build_trie(n);
        int ans=0;
        mat_qpow(0,L);
        for (int i=0;i<=tot;i++){
            ans+=M[1].mat[0][i];
            ans=ans%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(power oj 2790: GAUSS 2014(AC自动机fail数组运用+矩阵快速幂))