题目大意

在一种语言中的字母表中有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步存在多少种方法

总是从上一步推到下一步

写成滚动数组也不会有问题

这里要注意在AC自动机更新操作时,要将每个串末尾能到达的fail位置也记上标记,题解中有注释解释

 #include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define clr(x) memset(x , 0 , sizeof(x))
#define set(x) memset(x , -1 , sizeof(x))
typedef long long LL ;
#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )
map<char , int> mp; const int CHAR_SIZE = ;
const int MAX_SIZE = ;
const int M = ;
int n,m,p; struct BigInt {
int wei , a[];
BigInt(){
wei = ;
memset(a , , sizeof(a));
}
void init(){
wei = ;
memset(a , , sizeof(a));
}
void print(){
for(int i=wei- ; i>= ; i--) printf("%d" , a[i]);
printf("\n");
}
BigInt operator+(BigInt m){
BigInt ret;
int ma = max(wei , m.wei);
for(int i= ; i<ma ; i++){
ret.a[i] += a[i]+m.a[i];
if(ret.a[i]>=) ret.a[i+]++,ret.a[i]-=;
}
if(ret.a[ma]) ret.wei = ma+;
else ret.wei = ma;
return ret;
}
}; struct AC_Machine{
int ch[MAX_SIZE][CHAR_SIZE] , val[MAX_SIZE] , fail[MAX_SIZE];
int sz; void init(){
sz = ;
clr(ch[]) , clr(val);
} void insert(char *s){
int n = strlen(s);
int u= ;
for(int i= ; i<n ; i++){
int c = mp[s[i]];
if(!ch[u][c]){
clr(ch[sz]);
val[sz] = ;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = ;
} void get_fail(){
queue<int> Q;
fail[] = ;
for(int c= ; c<n ; c++){
int u = ch[][c];
if(u){Q.push(u);fail[u]=;}
}
while(!Q.empty()){
int r = Q.front();
Q.pop();
//比如is, history都是非法的,history中有is,那么history访问到它的s时也是非法的
val[r] |= val[fail[r]];
for(int c= ; c<n ; c++){
int u = ch[r][c];
if(!u){ch[r][c] = ch[fail[r]][c]; continue;}
fail[u] = ch[fail[r]][c];
Q.push(u);
}
}
}
}ac; char str[];
BigInt dp[MAX_SIZE][]; BigInt solve(int n , int step)
{
for(int i= ; i<ac.sz ; i++)
for(int j= ; j<=step ; j++){
dp[i][j].init();
}
dp[][].wei = dp[][].a[] = ;
for(int i= ; i<=step ; i++){
for(int j= ; j<ac.sz ; j++){
for(int k= ; k<n ; k++)
if(!ac.val[ac.ch[j][k]]){
dp[ac.ch[j][k]][i] = dp[ac.ch[j][k]][i]+dp[j][i-];
}
}
}
BigInt ret = BigInt();
for(int j= ; j<ac.sz ; j++) ret = ret+dp[j][step];
return ret;
} int main()
{
// freopen("in.txt" , "r" , stdin);
// freopen("out.txt" , "w" , stdout);
while(~scanf("%d%d%d" , &n , &m , &p)){
mp.clear();
getchar();
gets(str);
for(int i= ; i<strlen(str) ; i++) mp[str[i]] = i;
ac.init();
for(int i= ; i<=p ; i++){
gets(str);
ac.insert(str);
}
ac.get_fail();
BigInt ret = solve(n , m);
ret.print();
}
return ;
}

URAL 1158 AC自动机上的简单DP+大数的更多相关文章

  1. 【洛谷4045】[JSOI2009] 密码(状压+AC自动机上DP)

    点此看题面 大致题意: 给你\(n\)个字符串,问你有多少个长度为\(L\)的字符串,使得这些字符串都是它的子串.若个数不大于\(42\),按字典序输出所有方案. 状压 显然,由于\(n\)很小,我们 ...

  2. POJ 3691 AC自动机上的dp

    题目大意: 给定一些不合理的DNA序列,再给一段较长的dna序列,问最少修改几次可以使序列中不存在任何不合理序列,不能找到修改方法输出-1 这里你修改某一个点的DNA可能会影响后面,我们不能单纯的找匹 ...

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

    题意: 给你一个母串,多个模式串及其价值,求用模式串拼接成母串(不重叠不遗漏),能获得的最大价值. 分析: ac自动机中,在字典树上查找时,用dp,dp[i]拼成母串以i为结尾的子串,获得的最大价值, ...

  4. 【BZOJ1030】[JSOI2007] 文本生成器(AC自动机上跑DP)

    点此看题面 大致题意: 给你\(N\)个字符串(只含大写字母),要你求出有多少个由\(M\)个大写字母构成的字符串含有这\(N\)个字符串中的至少一个. \(AC\)自动机 看到题目,应该比较容易想到 ...

  5. Passwords Gym - 101174E (AC自动机上DP)

    Problem E: Passwords \[ Time Limit: 1 s \quad Memory Limit: 256 MiB \] 题意 给出两个正整数\(A,B\),再给出\(n\)个字符 ...

  6. BZOJ 1030 文本生成器 | 在AC自动机上跑DP

    题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1030 题解: 鸽 #include<cstdio> #include<al ...

  7. bzoj [Sdoi2014]数数 AC自动机上dp

    [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1264  Solved: 636[Submit][Status][Discu ...

  8. 【Luogu】P3311数数(AC自动机上DP)

    题目链接 蒟蒻今天终于学会了AC自动机,感觉很稳 (后一句愚人节快乐) 这题开一个f[i][j][k]表示有没有受到限制,正在枚举第j位,来到了AC自动机的第k个节点 的方案数 随后可以刷表更新 注意 ...

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

    Crazy Typewriter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

随机推荐

  1. POJ 3468(树状数组的威力)

    之前说过这是线段树的裸题,但是当看了http://kenby.iteye.com/blog/962159 这篇题解后我简直震惊了,竟然能如此巧妙地转化为用树状数组来处理,附上部分截图(最好还是进入原网 ...

  2. Image Cropper+java实现截图工具

    首先,请移步http://jquery-plugins.net/image-cropper-jquery-image-cropping-plugin下载iamge cropper的有关js文件及css ...

  3. 转!sqlServer2000 表连接查询

    在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...

  4. 开机使用root用户登录

    有的fedora版本默认不支持开机以root用户登录,这是出于安全机制的考虑,可以通过设置实现开机root用户登录 步骤: 1.修改.etc/pam.d/gdm文件,注释掉auth  pam_succ ...

  5. Windows菜单

    目录 第1章 Windows菜单    1 1.1 窗口菜单和弹出菜单    1 1.2 使用SetMenu    2 1.3 使用TrackPopupMenu    4 第1章 Windows菜单 ...

  6. 使用mybatis操作mysql数据库SUM方法返回NULL解决

    使用SQL语句用函数SUM叠加的时候,默认查询没有值的情况下返回的是NULL,而实际可能我们要用的是返回0 解决: SELECT SUM(total)   FROM test_table 改成: SE ...

  7. Eclipse小技巧

      Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当前行到上一行(复制增加)Alt+↓ ...

  8. php向数据库写数据逻辑

    先写php 文件 1.post请求 1)先确定传进来的数据有值 没有就退出程序 if(!isset($_POST['username'])){ die('没有传值') } 2)设config.php ...

  9. robotframework笔记10

    循环和条件 for循环 *** Settings *** Library BuiltIn Library Collections *** Test Cases *** TestCase01 My Ke ...

  10. [Jetty] jetty 内存调优

    在start.ini中配置代码如下 -Dcom.sun.management.jmxremote=true -Xmx6144m -XX:PermSize=256M -XX:MaxPermSize=10 ...