• 洛谷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 '
    '
    #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
  • 相关阅读:
    HTTP 返回状态代码详细解释
    丁一的作业
    getIntent().getExtras().clear()未清空Bundle的数据
    activity android:launchMode="singleTask" 没用重现启动activity的问题
    判断email格式
    判断网络是否可用
    修改系统语言
    生成UUID
    css reset file
    智能指针(auto_ptr)vc版
  • 原文地址:https://www.cnblogs.com/Anonytt/p/13446325.html
Copyright © 2020-2023  润新知