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. Spring事务(三)-事务传播行为

    在Spring里,一个事务方法被另外一个事务方法调用时,两个方法的事务应该如何进行,说白话一点,就是说当出现异常需要回滚时,各个方法的数据操作是否要全部回滚,事务传播行为就是决定了这样的一个处理结果. ...

  2. Linux系统设置shell开机自启

        自己写一个shell脚本 chmod -x file.sh sudo cp file.sh /etc/profile.d/ 将写好的脚本(.sh文件)放到目录 /etc/profile.d/ ...

  3. 基于泰凌微2.4G私有协议TLSR8359的遥控器解决方案之源码解析

    一 2.4G私有协议 在无线遥控和远距离无线通信领域,2.4G私有协议有着天然的优势.成本低,发射功率大,功耗低.这让它在远距离无线遥控飞机,遥控车等领域有着广泛的应用.基于TLSR8359市场上广泛 ...

  4. 公开的Webservice集锦

    备注:以下所有的来自 互联网,版权归原作者所有 股票行情数据 WEB 服务(支持香港.深圳.上海基金.债券和股票:支持多股票同时查询) Endpoint: http://webservice.webx ...

  5. GDB简洁指南

    启动gdb:gdb program 设置运行参数:set args 10 20 30 启动程序: run(r),start 显示源代码:list(l) 显示当前栈帧和运行行:frame(f) 设置显示 ...

  6. 应用层01-HTTP

    2.1 应用层协议原理 2.1.1 网络应用程序体系结构 研发网络应用的程序的核心是写出能够运行在不同的端系统和通过网络彼此通信的程序. 例如: Web应用程序 客户:浏览器程序(进程) 服务:Web ...

  7. SpringBoot集成drools

    目录 1.背景 2.需求 3.实现 3.1 引入jar包 3.2 编写drools配置类 3.3 编写Person对象 3.4 编写drl文件 3.5 编写kmodule.xml文件 3.6 编写Co ...

  8. 懂一点前端—Vue快速入门

    01. 什么是 Vue Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架,是当下很火的一个 JavaScript MVVM 库,是以 数据驱动和组件化 的思想构建的 ...

  9. C#中字典集合的两种遍历

    记录一下 Dictionary<string, string> dictionary = new Dictionary<string,string>(); foreach (s ...

  10. 攻防世界 gametime 使用IDA pro+OD动调

    自学犟种琢磨动调的一个记录,算是第一次动调的新手向,大佬请飘过 题目 准备工作--IDA pro(32X) 下载得到一个exe文件,首先丢到PE里面--无壳,32bit 丢到IDA pro(x32)里 ...