zoukankan      html  css  js  c++  java
  • POJ 1625(AC自动机+dp)

    传送门

    题面:

    Censored!

    Time Limit: 5000MS   Memory Limit: 10000K
    Total Submissions: 11233   Accepted: 3069

    Description

    The alphabet of Freeland consists of exactly N letters. Each sentence of Freeland language (also known as Freish) consists of exactly M letters without word breaks. So, there exist exactly N^M different Freish sentences. 

    But after recent election of Mr. Grass Jr. as Freeland president some words offending him were declared unprintable and all sentences containing at least one of them were forbidden. The sentence S contains a word W if W is a substring of S i.e. exists such k >= 1 that S[k] = W[1], S[k+1] = W[2], ...,S[k+len(W)-1] = W[len(W)], where k+len(W)-1 <= M and len(W) denotes length of W. Everyone who uses a forbidden sentence is to be put to jail for 10 years. 

    Find out how many different sentences can be used now by freelanders without risk to be put to jail for using it. 

    Input

    The first line of the input file contains three integer numbers: N -- the number of letters in Freish alphabet, M -- the length of all Freish sentences and P -- the number of forbidden words (1 <= N <= 50, 1 <= M <= 50, 0 <= P <= 10). 

    The second line contains exactly N different characters -- the letters of the Freish alphabet (all with ASCII code greater than 32). 

    The following P lines contain forbidden words, each not longer than min(M, 10) characters, all containing only letters of Freish alphabet. 

    Output

    Output the only integer number -- the number of different sentences freelanders can safely use.

    Sample Input

    2 3 1
    ab
    bb
    

    Sample Output

    5

    题意:

        有一个大小为n的字母表,你可以用这n种字母去造单词。现在有给你p个单词,让你造出一个长度为m的单词,使得你造出的单词不含有给定的p个单词。问你可以造出的方案数为多少。

    题目分析:

        类似bzoj1030,我们可以直接用dp去解决。

        我们设dp[i][j]为当前长度为i的字符串处于Trie树中的第j号结点所具有的方案数。

        根据AC自动机next数组的性质,我们不难发现,长度为i+1,位于第j个结点的方案数可以转移到长度为i,位于第next[j][k]结点的方案数,即dp[i+1][j]=dp[i+1][j]+dp[i][next[j][k]]。而当我们遍历到第j 个结点时发现它可以作为终止结点,我们就跳过该结点,此时就可以求出不符合条件(凑不出完整字符串)的方案数了。

        另外,这个题中没有对答案进行取模,因此还得需要贴上大数模板。

    代码:

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #define maxn 107
    using namespace std;
    map<char,int>mp;
    char st[maxn];
    char table[maxn];
    struct Trie{//AC自动机
        int next[maxn][60],fail[maxn],root,id,End[maxn],n;
        int newnode(){
            for(int i=0;i<51;i++){
                next[id][i]=-1;
            }
            End[id]=0;
            //cout<<id<<endl;
            return id++;
        }
        void init(int _n,char *str){
            id=0;
            n=_n;
            root=newnode();
            int len=strlen(str);
            mp.clear();
            for(int i=0;i<len;i++){
                mp[str[i]]=i;
            }
        }
        void Insert(char *str){
            int len=strlen(str);
            int now=root;
            for(int i=0;i<len;i++){
                if(next[now][mp[str[i]]]==-1){
                    next[now][mp[str[i]]]=newnode();
                    //cout<<id<<endl;
                }
                now=next[now][mp[str[i]]];
            }
            End[now]=1;
            //cout<<id<<endl;
        }
        void build(){
            queue<int>que;
            for(int i=0;i<n;i++){
                if(next[root][i]==-1){
                    next[root][i]=root;
                }
                else{
                    fail[next[root][i]]=root;
                    que.push(next[root][i]);
                }
            }
            while(!que.empty()){
                int now=que.front();
                que.pop();
                for(int i=0;i<n;i++){
                    if(next[now][i]==-1){
                        next[now][i]=next[fail[now]][i];
                    }
                    else{
                        fail[next[now][i]]=next[fail[now]][i];
                        que.push(next[now][i]);
                    }
                }
                End[now]|=End[fail[now]];
            }
            //cout<<id<<endl;
        }
    }ac;
    
    struct BigInteger{//大整数模板
        int A[25];
        enum{MOD = 10000};
        BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
        void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
        void print(){
            printf("%d", A[A[0]]);
            for (int i=A[0]-1; i>0; i--){
                if (A[i]==0){printf("0000"); continue;}
                for (int k=10; k*A[i]<MOD; k*=10) printf("0");
                printf("%d", A[i]);
            }
            printf("
    ");
        }
        int& operator [] (int p) {return A[p];}
        const int& operator [] (int p) const {return A[p];}
        BigInteger operator + (const BigInteger& B){
            BigInteger C;
            C[0]=max(A[0], B[0]);
            for (int i=1; i<=C[0]; i++)
                C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
            if (C[C[0]+1] > 0) C[0]++;
            return C;
        }
        BigInteger operator * (const BigInteger& B){
            BigInteger C;
            C[0]=A[0]+B[0];
            for (int i=1; i<=A[0]; i++)
                for (int j=1; j<=B[0]; j++){
                    C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
                }
            if (C[C[0]] == 0) C[0]--;
            return C;
        }
    };
    BigInteger dp[60][maxn];
    int main()
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        scanf("%s",table);
        ac.init(n,table);
        for(int i=0;i<k;i++){
            scanf("%s",st);
            ac.Insert(st);
        }
        ac.build();
        //cout<<ac.id<<endl;
        dp[0][0].set(1);
        for(int i=1;i<=m;i++){//dp转移
            for(int j=0;j<ac.id;j++){
                for(int k=0;k<n;k++){
                    if(ac.End[ac.next[j][k]]) continue;
                    dp[i][ac.next[j][k]]=dp[i-1][j]+dp[i][ac.next[j][k]];
                }
            }
        }
        BigInteger res;
        for(int i=0;i<ac.id;i++){
            res=res+dp[m][i];
        }
        res.print();
        return 0;
    }
    
  • 相关阅读:
    29Mybatis_整合ehcache以及应用场景
    28Mybatis_查询缓存-二级缓存-二级缓存测试-
    27Mybatis_一级缓存的实际应用场景
    解析分布式锁之Zookeeper实现(一)
    程序员的十年工作创业血泪史,万字长文,仔细读完,受益匪浅
    2018 Java线程热门面试题,你知道多少?
    看阿里P9架构师如何向你定义架构及架构师
    程序员30 岁之后:如何实现质的突破?
    强者自救,圣者渡人
    干货:通过双十一等项目实战看架构技术
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007223.html
Copyright © 2011-2022 走看看