洛谷P4052 [JSOI2007]文本生成器(AC自动机+DP)

题目链接:https://www.luogu.com.cn/problem/P4052

前言:

  学长说AC自动机的DP都非常套路

  大部分dp[i][j]表示当前在节点j,且串长为i时的情况,

  有时再加一维表示这个状态里面包含了哪些东西

  而且AC自动机的DP会经常让你用矩阵乘法优化

题解:

 

我个人想说的:也是第一次做AC自动机上的DP问题,一开始那里End为什么在转移的时候需要 |= 呢?因为有可能一个串的结尾原先insert进去后end为1,但是它的fail却是0,这个时候原先的1就会被0覆盖掉,所以用|=来维护当前的End。

 AC代码:

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e4+7;
class ac_auto{
    public:
        const static int maxn=5e4+100;
        int tot,root;
        int tree[maxn][30]; 
        int End[maxn];
        int fail[maxn];int ans[1005];
        int newnode(){
            for(int i=0;i<26;i++){
                tree[tot][i]=0;
            }
            End[tot]=0;
            return tot++;
        }
        void init(){
            mem(ans,0);tot=0;
            root=newnode();
        }                
        void insert_(string s){
            int now = root;
            for(int i=0;i<s.length();i++){
                int id=s[i]-'A';
                if(!tree[now][id]){
                    tree[now][id]=newnode();
                }
                now=tree[now][id];
            }
            End[now]|=1;
        }
        
        void getFail(){
            queue <int>q;
            for(int i=0;i<26;i++){
                if(tree[0][i]){
                    fail[tree[0][i]] = 0;
                    q.push(tree[0][i]);
                }
            }
            while(!q.empty()){
                int now = q.front();
                q.pop();
                for(int i=0;i<26;i++){
                    if(tree[now][i]){
                        fail[tree[now][i]] = tree[fail[now]][i];
                        End[tree[now][i]] |= End[tree[fail[now]][i]];
                        q.push(tree[now][i]);
                    }
                    else
                        tree[now][i] = tree[fail[now]][i];
                }
            }
        }    
}acam;
int dp[105][10005];
ll qp(ll a,ll b,ll c){
    ll ans = 1;
    ll base = a%c;
    while(b){
        if(b & 1) ans = (ans*base)%c;
        base = (base*base)%c;
        b >>= 1;
    }
    return ans;
}

int main(){
    int n,m;scanf("%d%d",&n,&m);
    acam.init();
    rep(i,1,n){
        string s;cin>>s;
        acam.insert_(s);
    }
    acam.getFail();
    dp[0][0]=1;
    rep(i,1,m){
        rep(j,0,acam.tot-1){
            rep(k,0,25){
                if(!acam.End[acam.tree[j][k]]){
                    dp[i][acam.tree[j][k]]=(dp[i][acam.tree[j][k]]+dp[i-1][j])%mod;
                }
            }
        }
    }
    int ans=0;
    rep(i,0,acam.tot-1){
        ans=(ans+dp[m][i])%mod;
    }
    ans=(qp(26,m,mod)-ans+mod)%mod;
    cout<<ans<<endl;
}
View Code

 

posted @ 2020-08-06 14:51  Anonytt  阅读(111)  评论(0编辑  收藏  举报