文本生成器


求可行方案數,可能容斥,但是操作過於complex,復雜度爆炸,不可做。

由於總方案數一定,為26^m,求不可行方案數,相減即可。此時的不可行方案數模型為求使一個字符串不含任何單詞的方案數。

那么我們定義dp[i][j],表示走i步(即路徑長度為i),到達Ac_automaton上第j個節點的方案數(應該是小套路),那么我們先給出沒有細節限制的狀態轉移方程:

dp[i][k]+=dp[i-1][j];(k是j的兒子節點)

那么我們想一下實現細節,首先我們的方程應該是不經過任何單詞的方案數,所以在單詞尾打標記是一定的,同時根據以往Ac_automaton的經驗,這個單詞被標記,則fail指向它的那些節點也應該被標記,因為該單詞是其他單詞的后綴,一旦其他單詞出現,則該單詞一定出現,不符合轉移要求,所以要打上標記。

然后在上述方程中,我們計算貢獻時是不能經過任何單詞的,所以一旦枚舉到有標記的節點直接continue掉。

最后統計答案時,有標記的節點不應該作出貢獻,可能有同學會問,我上面不是沒更新有標記節點嗎?他們不是0?實際上,我們只是沒讓這些節點去作出貢獻,而有的貢獻已經轉移到他們身上(自己去觀察一下方程)。

ans=26^m-sigma(dp[m][i])。

不要忘了取模法則。+個mod防負數。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int mod=10007;
int n,m;
char s[200];
struct Ac_automaton{
    int tot,root,ans,cnt;
    int trie[16000][26],fail[16000],v[16000];
    int dp[200][16000];
    void clear(){tot=root=ans=1;cnt=0;}
    void insert(){
        int l=strlen(s+1);
        int now=root;
        for(int i=1;i<=l;i++){
            if(!trie[now][s[i]-'A']) trie[now][s[i]-'A']=++tot;
            now=trie[now][s[i]-'A'];
        }v[now]=1;
    }
    void generate(){
        queue<int>q;
        for(int i=0;i<26;i++)
            if(trie[root][i]){
                fail[trie[root][i]]=root;
                q.push(trie[root][i]);
            }else trie[root][i]=root;
        while(!q.empty()){
            int now=q.front();
            q.pop();
            for(int i=0;i<26;i++)
                if(trie[now][i]){
                    fail[trie[now][i]]=trie[fail[now]][i];
                    v[trie[now][i]]|=v[fail[trie[now][i]]];
                    q.push(trie[now][i]);
                }else trie[now][i]=trie[fail[now]][i];
        }
    }
    int Dp(){
        dp[0][1]=1;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=tot;j++){
                if(v[j]) continue;
                for(int k=0;k<26;k++)
                    dp[i][trie[j][k]]=(dp[i][trie[j][k]]+dp[i-1][j])%mod;
            }
        for(int i=1;i<=tot;i++)
            if(!v[i]) cnt=(cnt+dp[m][i])%mod;
        for(int i=1;i<=m;i++)
            ans=(ans*26)%mod;
        return (ans%mod-cnt%mod+mod)%mod;
    }
}Acm;
int main(){
    scanf("%d%d",&n,&m);
    Acm.clear();
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        Acm.insert();
    }Acm.generate();
    printf("%d",Acm.Dp());
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM