poj--1625Censored!+AC自动机上的dp+大数

题目链接:点击进入

其实看起来是完全可以用矩阵做的,但是因为用到了大数的,导致内存开不下,所以用dp写了。其实dp的过程依旧就是在我们用禁止出现单词构建的trie上走m步的过程。我们定义dp[i][j]表示走过i步以后到达节点j的方案数,则状态转移应该是dp[i][j]=sum(dp[i-1][k]),其中k表示可以走到j的节点,并且不能是病毒节点。但是其实这样代码就不是那么好写了,其实我们可以用节点j主动的去更新它的子节点k,这样转移方程就成了dp[i][next[j][k]]+=dp[i-1][j]。要求next[j][k]不能使病毒节点。总而言之,AC自动机上的dp就是要利用我们建立的trie树以及上面的转移方式进行状态转移。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;

///大数模版
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("\n");
    }
    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;
    }
}One;

const int maxn=10*10+5;
char alph[maxn];
map<char,int>h;

int getIndex(char ch)
{
     return h[ch];
}

struct Trie
{
    int next[maxn][maxn/2],fail[maxn],flag[maxn];
    int root,L,len;
    int newnode()
    {
        memset(next[L],-1,sizeof(next[L]));
        flag[L++];
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }
    void insert(char buf[])
    {
        int len1=strlen(buf);
        int now=root;
        for(int i=0;i<len1;i++)
        {
            int index=getIndex(buf[i]);
            if(next[now][index]==-1)
               next[now][index]=newnode();
            now=next[now][index];
        }
        flag[now]=1;
    }
    void build()
    {
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i<len;i++)
        {
          if(next[root][i]==-1)
             next[root][i]=root;
          else
          {
              fail[next[root][i]]=root;
              Q.push(next[root][i]);
          }
        }
        while(!Q.empty())
        {
            int now=Q.front();
            if(flag[fail[now]])
               flag[now]++;
            Q.pop();
            for(int i=0;i<len;i++)
            {
                if(next[now][i]==-1)
                  next[now][i]=next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    //flag[next[now][i]]|=flag[next[fail[now]][i]];
                    Q.push(next[now][i]);
                }
            }
        }
    }
};

Trie ac;
char str[maxn];

BigInteger dp[maxn][maxn];

int main()
{
    int n,m,p;
    ///freopen("in.txt","r",stdin);
    One.set(1);
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        h.clear();
        scanf("%s",alph);
        for(int i=0;i<strlen(alph);i++)
           h[alph[i]]=i;
        ac.init();
        ac.len=strlen(alph);
        for(int i=0;i<p;i++)
        {
            scanf("%s",str);
            ac.insert(str);
        }
        ac.build();
        for(int i=0;i<=m;i++)
          for(int j=0;j<ac.L;j++)
             dp[i][j].set(0);
        dp[0][0].set(1);
        for(int i=1;i<=m;i++)
          for(int j=0;j<ac.L;j++)
            for(int k=0;k<n;k++)
            {
                if(ac.flag[ac.next[j][k]]) continue;
                dp[i][ac.next[j][k]]=dp[i][ac.next[j][k]]+dp[i-1][j];
            }
        BigInteger ans;
        ans.set(0);
        for(int i=0;i<ac.L;i++)
          ans=ans+dp[m][i];
        ans.print();
    }
  return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-31 08:21:30

poj--1625Censored!+AC自动机上的dp+大数的相关文章

POJ 3691 AC自动机上的dp

题目大意: 给定一些不合理的DNA序列,再给一段较长的dna序列,问最少修改几次可以使序列中不存在任何不合理序列,不能找到修改方法输出-1 这里你修改某一个点的DNA可能会影响后面,我们不能单纯的找匹配数,因为你找到了你也不一定有方法改变它 这里用DP来解决 判断到第i位dna , 之前dp值保存了前面dna所能到达的所有状态: dp[i][j] 也就是用了前i个dna所到达的状态至少需要修改的值 从所有状态出发,经过AGCT4种情况到达下一个状态,只要下一个状态不为非法状态即可 过程中只要判断

bzoj 1030: [JSOI2007]文本生成器 (ac自动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中

HNU 13108-Just Another Knapsack Problem (ac自动机上的dp)

题意: 给你一个母串,多个模式串及其价值,求用模式串拼接成母串(不重叠不遗漏),能获得的最大价值. 分析: ac自动机中,在字典树上查找时,用dp,dp[i]拼成母串以i为结尾的子串,获得的最大价值,dp[i]=max(dp[i],dp[i-len]+val[tmp]).,len是模式串的长度,val[tmp]为其价值. #include <cstdio> #include <cstring> #include <cmath> #include <queue>

URAL 1158 AC自动机上的简单DP+大数

题目大意 在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词.但是有P(P<=10)个串是被禁止的,也就是说,任何单词的子串都不能包含这P个串中的任意一个.问按照上述规则,能产生的合法串一共有多少个? 例如:N=3 M=3 P=3 字母表中的三个字符是QWE 被禁止的串为”QQ”,”WEE”,”Q”,则合法的串一共有7个. 这题目相当于通过步数对AC自动机上每一个点的状态进行DP dp[i][j]表示到达i这个点,走了j

POJ2778 DNA Sequence AC自动机上dp

网址:https://vjudge.net/problem/POJ-2778 题意: 给出字符集${A,C,G,T}$和一些字符串(长度不超过$10$,且数量不超过$10$个),求长度为$n(n \leq 2e9)$的字符串中不包括上面这些字符串的字符串的数量. 题解: 我们可以先考虑一种方式:设$dp(i,j)$是用了$i$个字符拼出符合题意的长度为$j$的字符串的数量,在本题中$dp(i,j)=\sum _{j' \subseteq j} dp(i-1,j')$,显然时间复杂度是指数级的,不

hdu 3247 AC自动+状压dp+bfs处理

Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)Total Submission(s): 2382    Accepted Submission(s): 750 Problem Description Great! Your new software is almost finished! The only thing left to

hdu 3992 AC自动机上的高斯消元求期望

Crazy Typewriter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 391    Accepted Submission(s): 109 Problem Description There was a crazy typewriter before. When the writer is not very sober, it

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而

UVA 11468(Substring-AC自动机上dp)[Template:AC自动机]

Substring Given a set of pattern strings, and a text, you have to find, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print "yes", otherwise "no" (without quotes). But, unfort