[JSOI2007]文本生成器

问题描述

对于一个长度为 \(n\) 的串 \(S\) ,有多少可能情况的串 \(S\) 使得 \(S\) 的子串中至少包含一个给定的串,给定的串有 \(m\)

解法

由多模式串匹配想到AC自动机,由计数想到dp

首先建好Trie图,更新所有end标记。记 \(dp[now][st][flag]\) 表示当前正在匹配第 \(st\) 位,已确定的串匹配到了Trie图上的 \(now\) 号节点,\(flag\) 表示是否已经出现过给定的模式串。总共有 \((\sum_{i=1}^{m} |s_i|)\times n \times 2\) 种状态,显然要记忆化搜索。对于每个状态枚举下一位所有可能的 \(26\) 位字符,并在Trie图上进行节点转移,flag或上end标记,最后累加答案。当 \(st=n+1\) 即已经匹配完成时,返回值为flag的状态(显然若有给定字符串则贡献 \(1\) 的答案)。最终的结果为初始状态 \(dp[0][1][false]\)

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define Mod 10007
#define N 107

template<class T>
inline void read(T &x){
    x=0;char c=getchar();T flag=1;
    while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    x*=flag;
}

struct Trie{
    int vis[26],fail,end;
}go[N*100];

int cnt=0,n,m,f[N*100][N][2];
char s[N];
queue<int> Q;

inline void insert(){
    int now=0,len=strlen(s);
    for(int i=0;i<len;i++){
        int to=s[i]-'A';
        if(!go[now].vis[to])
            go[now].vis[to]=++cnt;
        now=go[now].vis[to];
    }
    go[now].end=1;
}
inline void Get_fail(){
    for(int i=0;i<26;i++)
        if(go[0].vis[i]) Q.push(go[0].vis[i]);
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=0;i<26;i++)
            if(go[u].vis[i]){
                go[go[u].vis[i]].fail=go[go[u].fail].vis[i];
                go[go[u].vis[i]].end|=go[go[go[u].fail].vis[i]].end;
                Q.push(go[u].vis[i]);
            }else go[u].vis[i]=go[go[u].fail].vis[i];
    }
}
int dfs(int now,int st,bool flag){
    if(st==m+1) return flag;
    if(f[now][st][flag]!=-1) return f[now][st][flag];
    f[now][st][flag]=0;int ret=0;
    for(int i=0;i<26;i++){
        int to=go[now].vis[i];
        ret=(ret+dfs(to,st+1,flag|go[to].end))%Mod;
    }
    return f[now][st][flag]=ret;
}
int main(){
//    freopen("dict.in","r",stdin);
//    freopen("dict.out","w",stdout);
    memset(f,-1,sizeof(f));
    read(n);read(m);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert();
    }
    Get_fail();
    printf("%d",dfs(0,1,false));
}
/*
2 2
AB
BA
*/
posted @ 2020-08-23 20:58  Kreap  阅读(131)  评论(0编辑  收藏  举报