bzoj4861 / P3715 [BJOI2017]魔法咒语
AC自动机+dp+矩阵乘法
常规思路是按基本串建立AC自动机
然鹅这题是按禁忌串建立AC自动机
对后缀是禁忌的点以及它的失配点做上标记$(a[i].ed)$,到时候不访问。
基本串转化为自动机上的边:设$p[j][i]$表示第$j$个节点加上第$i$个串会到的节点编号
在建好AC自动机后可以直接处理。
现在分类讨论(对,两份代码)
1.$L<=100,60pts$
直接在AC自动机上跑dp
设$f[j][i]$表示到点$j$长度为$i$的方案数
枚举基本串$1~k$,显然$f[p[j][k]][i+size[k]]+=f[j][i]$
$sz$表示AC自动机的节点数,则$ans=\sum_{i=0}^{sz}f[i][L]*[a[i].ed==0]$
2.基本词汇长度不超过$2,40pts$
开个$maxn*2$的矩阵,矩阵乘法瞎搞。
$f[i][L]=\sum_{j}f[j][l-1],j->i$
对于长度为2的情况,就开2倍的数组,用$i*2+1$暂时保存。
注意下标从0开始
(为啥我的常数这么大呢......)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define N 105
const int mod=1e9+;
int ans,sz,n,m,L,siz[N],f[N][N],p[N][N];
char q[N],s[N][N];
queue <int> h; struct node{int nxt[],f,ed;}a[];
void add(){
scanf("%s",q);
int len=strlen(q),u=;
for(int i=;i<len;++i){
if(!a[u].nxt[q[i]-'a'])
a[u].nxt[q[i]-'a']=++sz;
u=a[u].nxt[q[i]-'a'];
}a[u].ed=;
}
void acbuild(){
for(int i=;i<;++i) if(a[].nxt[i]) h.push(a[].nxt[i]);
while(!h.empty()){
int x=h.front();h.pop();
for(int i=;i<;++i){
int &to=a[x].nxt[i];
if(to){
a[to].f=a[a[x].f].nxt[i];
a[to].ed|=a[a[to].f].ed;
h.push(to);
}else to=a[a[x].f].nxt[i];
}
}
} struct mat{
int A[][];
mat(){memset(A,,sizeof(A));}
mat operator * (mat &tmp) const{
mat c;int w=sz<<|;
for(int i=;i<=w;++i)
for(int j=;j<=w;++j)
for(int k=;k<=w;++k)
c.A[i][j]=(c.A[i][j]+1ll*A[i][k]*tmp.A[k][j]%mod)%mod;
return c;
}
};
mat Pow(mat x,int y){
mat rs;
for(int i=;i<=sz;++i)
rs.A[i<<][i<<]=;
for(;y;y>>=,x=x*x)
if(y&) rs=rs*x;
return rs;
} void task1(){
f[][]=;
for(int i=;i<L;++i)
for(int j=;j<=sz;++j)
if(f[j][i])
for(int k=;k<=n;++k)
if(p[j][k]!=-&&i+siz[k]<=L)
f[p[j][k]][i+siz[k]]=(f[p[j][k]][i+siz[k]]+f[j][i])%mod;
for(int i=;i<=sz;++i) if(!a[i].ed) ans=(ans+f[i][L])%mod;
}
void task2(){
mat res;
for(int i=;i<=sz;++i){
for(int j=;j<=n;++j)
if(p[i][j]!=-){
if(siz[j]==) ++res.A[p[i][j]<<][i<<];
else ++res.A[p[i][j]<<][i<<|];
}
res.A[i<<|][i<<]=;
}res=Pow(res,L);
for(int i=;i<=sz;++i) if(!a[i].ed) ans=(ans+res.A[i<<][])%mod;
}
int main(){
memset(p,-,sizeof(p));
scanf("%d%d%d",&n,&m,&L);
for(int i=;i<=n;++i) scanf("%s",s[i]),siz[i]=strlen(s[i]);
for(int i=;i<=m;++i) add();
acbuild();
for(int i=;i<=n;++i)
for(int j=,u=;j<=sz;u=++j){
for(int k=;k<siz[i]&&!a[u].ed;++k)
u=a[u].nxt[s[i][k]-'a'];
if(!a[u].ed) p[j][i]=u;
}
if(L<=) task1();
else task2();
printf("%d",ans);
return ;
}
bzoj4861 / P3715 [BJOI2017]魔法咒语的更多相关文章
- P3715 [BJOI2017]魔法咒语
P3715 [BJOI2017]魔法咒语 用基本词汇组成\(L\)长度的单词,其中不能包含禁忌词汇 用禁忌词汇建强大的\(tire\)图 解决: 分类讨论,\(L<=100\)用普通dp暴力在\ ...
- [BJOI2017]魔法咒语 --- AC自动机 + 矩阵优化
bzoj 4860 LOJ2180 洛谷P3175 [BJOI2017]魔法咒语 题目描述: Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无 ...
- Luogu-3250 [BJOI2017]魔法咒语(AC自动机,矩阵快速幂)
Luogu-3250 [BJOI2017]魔法咒语(AC自动机,矩阵快速幂) 题目链接 题解: 多串匹配问题,很容易想到是AC自动机 先构建忌讳词语的AC自动机,构建时顺便记录一下这个点以及它的所有后 ...
- 【BZOJ4861】[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP
[BZOJ4861][Beijing2017]魔法咒语 题意:别看BZ的题面了,去看LOJ的题面吧~ 题解:显然,数据范围明显的分成了两部分:一个是L很小,每个基本词汇长度未知:一个是L很大,每个基本 ...
- [BZOJ4861][BJOI2017]魔法咒语(AC自动机+矩阵优化DP)
4861: [Beijing2017]魔法咒语 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 217 Solved: 105[Submit][Sta ...
- 【[BJOI2017]魔法咒语】
矩阵乘法+\(AC\)自动机 是道很不错的题了 首先是前六十分,就是一个\(AC\)自动机上的套路\(dp\),设\(dp[i][j]\)表示匹配出的长度为\(i\)在自动机上位置为\(j\)的方案数 ...
- [BJOI2017]魔法咒语
Description Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后, Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术.这也多亏 Chandra ...
- AHOI2018训练日程(3.10~4.12)
(总计:共90题) 3.10~3.16:17题 3.17~3.23:6题 3.24~3.30:17题 3.31~4.6:21题 4.7~4.12:29题 ZJOI&&FJOI(6题) ...
- AC 自动机学习笔记
虽然 NOIp 原地爆炸了,目前进入 AFO 状态,但感觉省选还是要冲一把,所以现在又来开始颓字符串辣 首先先复习一个很早很早就学过但忘记的算法--自动 AC AC自动机. AC 自动机能够在 \(\ ...
随机推荐
- [Java in NetBeans] Lesson 04. Class / Objects
这个课程的参考视频和图片来自youtube. 主要学到的知识点有: Class: Blueprint for an object. (e.g. dog is a class) Object: cust ...
- [LeetCode] 598. Range Addition II_Easy tag: Math
做个基本思路可以用 brute force, 但时间复杂度较高. 因为起始值都为0, 所以肯定是左上角的重合的最小的长方形就是结果, 所以我们求x, y 的最小值, 最后返回x*y. Code ...
- 基于jquery ajax的多文件上传进度条
效果图 前端代码,基于jquery <!DOCTYPE html> <html> <head> <title>主页</title> < ...
- JAVA_Stream_练习
package airycode_java8.nice7; import airycode_java8.nice1.Employee; import org.junit.Test; import ja ...
- Spring中集合注入方法
集合注入重要是对数组.List.Set.map的注入,具体注入方法请参照一下代码(重点是applicationContext.xml中对这几个集合注入的方式): 1.在工程中新建一个Departmen ...
- sql server case
use mytest go exec p_city 2,4 exec p_city_cnt 2,3 select stuff((select ',' + city_id from cities for ...
- python2.7之乱码问题
python 3之后当然不存在乱码问题了.python 2的乱码问题有时就有点头疼了.(代码均为在windows下测试) 示例:保存为test1.py 报错信息如下: 解决办法: 我将代码保存为tes ...
- Linux 压缩解压缩命令详解
tar -c: 建立压缩档案-x:解压-t:查看内容-r:向压缩归档文件末尾追加文件-u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个.下面的 ...
- 关于CTeX的几个大坑
https://blog.csdn.net/zjutczj/article/details/53463478 最近一直忙着写小论文,毕业设计中期答辩,没有更新博客,忙过这一阵我会把这段时间学习机器学习 ...
- 大数据处理框架之Strom:redis storm 整合
storm 引入redis ,主要是使用redis缓存库暂存storm的计算结果,然后redis供其他应用调用取出数据. 新建maven工程 pom.xml <project xmlns=&qu ...