1. 程式人生 > >[bzoj1030][JSOI2007]文字生成器——AC自動機+動態規劃

[bzoj1030][JSOI2007]文字生成器——AC自動機+動態規劃

題目大意:

給定n個給定的串,求有多少個串滿足存在給定的串是這個串的子串。

思路:

直接計算存在的不太好算,考慮反面計數,計算有多少個串找不到匹配。
那麼當我們把AC自動機給建出來之後,不難發現一個滿足要求的串會一直在AC自動機上面跳並且到不了已經匹配上的節點,於是問題便轉化成了有向圖的路徑計數。
考慮DP,記dp[i][j]表示走了i步走到了第j個節點,每一個點列舉下一個字元是什麼,直接在AC自動機上轉移即可。

#include<bits/stdc++.h>
 
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;
 
using namespace std;
 
void File(){
    freopen("bzoj1030.in","r",stdin);
    freopen("bzoj1030.out","w",stdout);
}
 
template<typename T>void read(T &_){
    _=0; T f=1; char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    _*=f;
}
 
const int maxn=6000+10;
const int mod=1e4+7;
int n,m,dp[110][maxn];
int ch[maxn][26],num[maxn],fail[maxn],cnt=1;
 
void insert(char *s){
    int len=strlen(s+1),u=1,c;
    REP(i,1,len){
        c=s[i]-'A';
        if(!ch[u][c])ch[u][c]=++cnt;
        u=ch[u][c];
    }
    ++num[u];
}
 
void build_fail(){
    int h=1,t=0,q[maxn];
    fail[1]=1;
    REP(i,0,25){
        int v=ch[1][i];
        if(v)q[++t]=v;
        if(v)fail[v]=1;
        else ch[1][i]=1;
    }
    while(h<=t){
        int u=q[h++];
        REP(i,0,25){
            int v=ch[u][i];
            if(v)q[++t]=v;
            if(v){
                fail[v]=max(ch[fail[u]][i],1);
                num[v]|=num[fail[v]];
            }
            else ch[u][i]=max(ch[fail[u]][i],1);
        }
    }
}
 
void ad(int &x,int y){x=(x+y)%mod;}
 
void work(){
    dp[1][1]=1;
    REP(i,1,m)REP(j,1,cnt)REP(k,0,25)
        if(!num[ch[j][k]])
            ad(dp[i+1][ch[j][k]],dp[i][j]);
    int ans=1;
    REP(i,1,m)ans=ans*26%mod;
    REP(i,1,cnt)ad(ans,-dp[m+1][i]);
    printf("%d\n",(ans+mod)%mod);
}
 
int main(){
    //File();
    char s[maxn];
 
    read(n); read(m);
    REP(i,1,n){
        scanf("%s",s+1);
        insert(s);
    }
 
    build_fail();
 
    work();
    //cout<<"÷"<<endl;
    return 0;
}