• BZOJ 1030 AC自动机+DP


    询问由26个字母组成的长度为n的字符串中含有给定一些字符串为子串的种数。

    考虑补集。我们求出不含有给定字符串为子串的种数。

    这个问题可以由AC自动机上DP求得。

    对给定的串建立AC自动机。我们令dp[i][j]表示字符串第i位走到AC自动机上j节点的方法数。那么对应于一个字符串,就相当于AC自动机走到了某个节点的位置。

    现在由于不能包含某些字符串为子串,那么这个子串的end节点一定不能走,fail指针指向这些子串的end节点的节点也不能走。

    剩下的就可以进行DP了。那么dp[i][ch[j][k]]+=dp[i-1][j].

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 10007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=6010;
    //Code begin...
    
    int trie[N][27], top, fail[N], dp[105][N];
    
    void init(){top=1; mem(trie[0],0);}
    void ins(char *s){
        int rt, nxt;
        for (rt=0; *s; rt=nxt, ++s){
            nxt=trie[rt][*s-'A'];
            if (!nxt) mem(trie[top],0), trie[rt][*s-'A']=nxt=top++;
        }
        trie[rt][26]=1;
    }
    void makefail(){
        int u, v, bg, ed;
        static int q[N];
        fail[0]=bg=ed=0;
        FO(i,0,26) if ((v=trie[0][i])) fail[q[ed++]=v]=0;
        while (bg<ed){
            u=q[bg++];
            FO(i,0,26) {
                if ((v=trie[u][i])) fail[q[ed++]=v]=trie[fail[u]][i];
                else trie[u][i]=trie[fail[u]][i];
            }
            trie[u][26]|=trie[fail[u]][26];
        }
    }
    int work(int m){
        int ans1=1, ans2=0;
        FOR(i,1,m) ans1=ans1*26%MOD;
        dp[0][0]=1;
        FOR(i,1,m) FO(j,0,top) {
            if (trie[j][26]) continue;
            FO(k,0,26) dp[i][trie[j][k]]=(dp[i][trie[j][k]]+dp[i-1][j])%MOD;
        }
        FO(i,0,top) if (!trie[i][26]) ans2=(ans2+dp[m][i])%MOD;
        return ((ans1-ans2)%MOD+MOD)%MOD;
    }
    char str[105];
    int main ()
    {
        int n, m;
        scanf("%d%d",&n,&m); init();
        FOR(i,1,n) scanf("%s",str), ins(str);
        makefail();
        printf("%d
    ",work(m));
        return 0;
    }
    View Code
  • 相关阅读:
    寒假学习进度报告(一)
    【web】公文流转系统制作进度(一)(2019/12/9)
    【规律】A Rational Sequence
    【记忆化搜索】Happy Happy Prime Prime
    【背包问题】PACKING
    【动态规划】正则表达式匹配
    【数据结构】P1310 表达式的值
    【数据结构】P1449 后缀表达式
    【数据结构】P1054 等价表达式
    【数据结构】表达式求值
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6704201.html
Copyright © 2020-2023  润新知