B 组都说看不懂……我也解释不清啊……只能写这么详细了

其实就是道板题

省流:f[i][s][j]表示字符串长度i,匹配情况s,ac自动机节点j

Problem Description

给定k个字符串以及长度为n的母串可选字母的集合,问母串要完整出现给定的k个字符串的方案数,答案模1000000007,字符仅包含小写字母。

Input

第一行两个整数n、k,表示字符串的长度和给定字符串的个数。

接下来k行每行一个字符串。

接下来一行1个整数m表示可选字母集合内元素个数。

接下来一行给出一个长为m的字符串,表示字母的集合(可能有重复)。

Output

一个整数ans,表示方案数。

Sample Input Copy

3 2
cr
rh
4
acrh

Sample Output Copy

1
【样例解释】
只有crh符合。

Data Constraint

30%的数据n<=10,m<=3。

60%的数据n<=40。

另有10%的数据k=0。

另有10%的数据m=1。

100%的数据n<=100,m<=10,k<=8,给定字符串长度<=30。


先想一个弱化版问题:给定 \(k\) 个模式串以及长度为 \(n\) 的母串可选字母的集合,对于一个母串,它的价值为出现模式串的个数。问所有合法母串的价值和。

怎么才能判定一个母串是否包含几个模式串?

我们可以想到 ac 自动机,考虑对模式串建 ac 自动机,定义 tail 为以一个节点为模式串结尾的个数。如果我们跑到了一个标记为 tail 的节点,说明我们的母串包含了这一个模式串。

模仿 ac 自动机的过程,用 \(f[i][j]\) 表示母串长度为 \(i\),走到了自动机上的节点 \(j\) 的价值和,然后枚举它的下一个字符 \(c\),明显有 \(f[i+1][son[j][c]]\gets f[i][j] + tail[son[j][c]]\)。


回到原问题,因为我们要求完整出现给定的 \(k\) 个模式串的方案数,所以我们状压模式串的出现情况为 \(s\)。

然后定义 tail 为以一个节点为模式串结尾的状压出现情况

同时,我们在 ac 自动机中有一个跳 fail 的步骤,这个步骤不是线性的,因为我们此时已经状压了,就可以直接在建树时把它传给子节点,有 \(tail[u]|=tail[fail[u]]\)。

所以我们设 \(f[i][s][j]\) 表示我们母串的长度为 \(i\),模式串的匹配状态为 \(s\)(状压后),当前母串跑到了 ac 自动机的节点 \(j\) 的方案数。

明显有 \(f[i+1][s|tail[son[j][c]]][son[j][c]]\gets f[i][s][j]\)。

#include <cstdio>
#include <queue>
using namespace std;
#define N 110
#define M 32
#define K 8
#define P 1000000007
int n, m, k, cnt, ans;
char s[M];
int can[M];
int f[2][1<<K][N*M];
int nxt[N*M][26];
int tail[N*M];
int fail[N*M];
bool vis[26];
void insert(int x) {
int p = 0;
for(int i = 1; s[i] != '\0'; i++) {
if(!nxt[p][s[i]-'a']) {
nxt[p][s[i]-'a'] = ++cnt;
}
p = nxt[p][s[i]-'a'];
}
tail[p] |= (1 << x);
}
void build() {
queue<int> q;
for(int i = 1; i <= m; i++)
if(nxt[0][can[i]]) q.push(nxt[0][can[i]]);
while(!q.empty()) {
int p = q.front();
q.pop();
tail[p] |= tail[fail[p]];
for(int i = 1; i <= m; i++) {
if(nxt[p][can[i]]) {
fail[nxt[p][can[i]]] = nxt[fail[p]][can[i]];
q.push(nxt[p][can[i]]);
} else {
nxt[p][can[i]] = nxt[fail[p]][can[i]];
}
}
}
}
int main() {
scanf("%d %d", &n, &k);
for(int i = 0; i < k; i++) {
scanf("%s", s+1);
insert(i);
}
scanf("%d", &m);
m = 0;
scanf("%s", s+1);
for(int i = 1; s[i] != '\0'; i++) {
if(!vis[s[i]-'a']) {
vis[s[i]-'a'] = 1;
can[++m] = s[i]-'a';
}
}
build();
f[0][0][0] = 1;
for(int i = 0; i < n; i++) {
for(int s = 0; s < (1<<k); s++) {
for(int p = 0; p <= cnt; p++) {
f[(i+1) % 2][s][p] = 0;
}
}
for(int s = 0; s < (1<<k); s++) {
for(int p = 0; p <= cnt; p++) {
if(!f[i%2][s][p]) continue;
for(int j = 1; j <= m; j++) {
int pp = nxt[p][can[j]];
(f[(i+1) % 2][s | tail[pp]][pp] += f[i%2][s][p]) %= P;
}
}
}
}
for(int i = 0; i <= cnt; i++) {
(ans += f[n%2][(1<<k)-1][i]) %= P;
}
printf("%d", ans);
}

【NOIP2013模拟联考8】匹配(match) 题解的更多相关文章

  1. JZOJ【NOIP2013模拟联考14】隐藏指令

    JZOJ[NOIP2013模拟联考14]隐藏指令 题目 Description 在d维欧几里得空间中,指令是一个长度为2N的串.串的每一个元素为d个正交基的方向及反方向之一.例如,d = 1时(数轴) ...

  2. JZOJ 3493. 【NOIP2013模拟联考13】三角形

    3493. [NOIP2013模拟联考13]三角形(triangle) (File IO): input:triangle.in output:triangle.out Time Limits: 10 ...

  3. JZOJ 3487. 【NOIP2013模拟联考11】剑与魔法(dragons)

    3487. [NOIP2013模拟联考11]剑与魔法(dragons) (Standard IO) Time Limits: 1000 ms  Memory Limits: 131072 KB  De ...

  4. JZOJ 3470. 【NOIP2013模拟联考8】最短路(path)

    470. [NOIP2013模拟联考8]最短路(path) (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed ...

  5. JZOJ 3463. 【NOIP2013模拟联考5】军训

    3463. [NOIP2013模拟联考5]军训(training) (Standard IO) Time Limits: 2000 ms  Memory Limits: 262144 KB  Deta ...

  6. JZOJ 3462. 【NOIP2013模拟联考5】休息(rest)

    3462. [NOIP2013模拟联考5]休息(rest) (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed ...

  7. JZOJ 3461. 【NOIP2013模拟联考5】小麦亩产一千八(kela)

    3461. [NOIP2013模拟联考5]小麦亩产一千八(kela) (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB  Det ...

  8. 【NOIP2013模拟联考7】OSU

    [NOIP2013模拟联考7]OSU 描述 Description osu 是一款群众喜闻乐见的休闲软件. 我们可以把osu的规则简化与改编成以下的样子: 一共有n次操作,每次操作只有成功与失败之分, ...

  9. [jzoj]3468.【NOIP2013模拟联考7】OSU!(osu)

    Link https://jzoj.net/senior/#main/show/3468 Description osu 是一款群众喜闻乐见的休闲软件. 我们可以把osu的规则简化与改编成以下的样子: ...

  10. 【NOIP2013模拟联考6】选课

    题目 你真的认为选课是那么容易的事吗?HYSBZ的ZY同志告诉你,原来选课也会让人产生一种想要回到火星的感觉.假设你的一周有n天,那么ZY编写的选课系统就会给你n堂课.但是该系统不允许在星期i和星期i ...

随机推荐

  1. [VueJsDev] 快速入门 - vue项目根目录配置文件

    [VueJsDev] 目录列表 https://www.cnblogs.com/pengchenggang/p/17037320.html vue项目根目录配置文件 ::: details 目录 目录 ...

  2. 安装libevent

    1.在libevent官网(http://libevent.org/)上下载压缩包(我下载的是libevent-2.1.8-stable.tar.gz) 2.解压压缩包:tar -zxvf libev ...

  3. C++中虚表是什么

    虚函数表,以及虚函数指针是实现多态性(Polymorphism)的关键机制.多态性允许我们通过基类的指针或引用来调用派生类的函数 定义 虚函数(Virtual Function) 定义:类中使用vir ...

  4. .Net 8.0 除gRPC之外的另一个选择,IceRPC之快束开始HelloWorld

    作者引言 很高兴啊,我们来到了第一篇,程序员的HelloWorld,快速开始RPC之游 快速入门 演示如何在几分钟内,使用IceRPC,构建和运行一个完整的客户端-服务器(C/S)应用程序. 必要条件 ...

  5. 【Docker】Windows将docker下载的镜像存放到其他盘

    1.在D盘创建一个存放docker虚拟机的文件夹,如下面图中所示: 2.创建好以后,找到桌面右下角的docker图标,在上面点右键,选择settings,打开docker的设置界面. 3.然后在doc ...

  6. 关于Actor Component的思考--学习斯坦佛UE+C++

    跟着B站的视频学习,感觉自己的头很混乱.所以浅浅总结一下创建Actor Component之后其的作用和相关操作. Actor Component 首先Component为一个组件,源码就是一个类的声 ...

  7. 【Java】try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后?

    try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后? package com.test ...

  8. 网站优化之开启tomcat的gzip压缩传输特性

    本文于2015年底完成,发布在个人博客网站上. 考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来. 基于tomcat 8.0.x版本的文档,可以了解到tomcat支持基于g ...

  9. OpenHarmony AI框架开发指导

    一.概述 1.功能简介 AI 业务子系统是 OpenHarmony 提供原生的分布式 AI 能力的子系统.AI 业务子系统提供了统一的 AI 引擎框架,实现算法能力快速插件化集成. AI 引擎框架主要 ...

  10. Python 学习路线:介绍、基础语法、数据结构、算法、高级主题、框架及异步编程详解

    Python 介绍 Python 是一种 高级 的.解释型 的.通用 的编程语言.其设计哲学强调代码的可读性,使用显著的缩进.Python 是 动态类型 和 垃圾收集 的. 基本语法 设置 Pytho ...