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]魔法咒语的更多相关文章

  1. P3715 [BJOI2017]魔法咒语

    P3715 [BJOI2017]魔法咒语 用基本词汇组成\(L\)长度的单词,其中不能包含禁忌词汇 用禁忌词汇建强大的\(tire\)图 解决: 分类讨论,\(L<=100\)用普通dp暴力在\ ...

  2. [BJOI2017]魔法咒语 --- AC自动机 + 矩阵优化

    bzoj 4860   LOJ2180   洛谷P3175 [BJOI2017]魔法咒语 题目描述: Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无 ...

  3. Luogu-3250 [BJOI2017]魔法咒语(AC自动机,矩阵快速幂)

    Luogu-3250 [BJOI2017]魔法咒语(AC自动机,矩阵快速幂) 题目链接 题解: 多串匹配问题,很容易想到是AC自动机 先构建忌讳词语的AC自动机,构建时顺便记录一下这个点以及它的所有后 ...

  4. 【BZOJ4861】[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP

    [BZOJ4861][Beijing2017]魔法咒语 题意:别看BZ的题面了,去看LOJ的题面吧~ 题解:显然,数据范围明显的分成了两部分:一个是L很小,每个基本词汇长度未知:一个是L很大,每个基本 ...

  5. [BZOJ4861][BJOI2017]魔法咒语(AC自动机+矩阵优化DP)

    4861: [Beijing2017]魔法咒语 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 217  Solved: 105[Submit][Sta ...

  6. 【[BJOI2017]魔法咒语】

    矩阵乘法+\(AC\)自动机 是道很不错的题了 首先是前六十分,就是一个\(AC\)自动机上的套路\(dp\),设\(dp[i][j]\)表示匹配出的长度为\(i\)在自动机上位置为\(j\)的方案数 ...

  7. [BJOI2017]魔法咒语

    Description Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后, Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术.这也多亏 Chandra ...

  8. 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题) ...

  9. AC 自动机学习笔记

    虽然 NOIp 原地爆炸了,目前进入 AFO 状态,但感觉省选还是要冲一把,所以现在又来开始颓字符串辣 首先先复习一个很早很早就学过但忘记的算法--自动 AC AC自动机. AC 自动机能够在 \(\ ...

随机推荐

  1. map的使用方式之一。

    map有返回值 foreach 没得.. 得到结果 可以把里面的值以数组的方式取出来: 举例:

  2. jenkins 常见问题汇总

    1.jenkins api调用 https://my.oschina.net/sanpeterguo/blog/197931 其中,有个错误的地方,带参数构建时,使用的时POST方法,如下: curl ...

  3. [pat]1045 Favorite Color Stripe

    1.用一个数组里面存储喜爱数字的值来区分数字是不是喜爱,以及值的大小顺序,用vector循环删除a数组中不是喜爱的元素,这里it=erase()之后it自动指向下一个元素,由于循环每次还要自增1,所以 ...

  4. apache分割数组和集合的分法

    public static void main(String[] agrs){    String[] array={"1","2","", ...

  5. vmware相关设置

    vmware虚拟机和宿主机共享文件夹 点击“虚拟机”->“设置” 进入之后,选择“选项”选项卡->选择“共享文件夹”(此处已启用实在安装VMware Tools时选择了启用共享文件夹功能) ...

  6. 转 EasyUi日期控件datebox设置,只显示年月,也只能选择年月

    1.引入Jquery和easyui,注低版本的Jquery和easy不能使用,这里使用的Jquery是1.8.2easyui是1.6.1.1.easyui下载地址:http://www.jeasyui ...

  7. linux telnet命令

    telnet命令通常用来远程登录.telnet程序是基于TELNET协议的远程登录客户端程序.Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户 ...

  8. css抖动动画

    button{ animation: beat 6s ease 0s infinite normal; } @keyframes beat { 0% { transform: translateY(0 ...

  9. jQuery-导航下拉菜单-实用简单

    /*CSS代碼*/ /*導航*/ .nav{background: url("../img/menu_bar.gif") repeat-x;} .nav ul li{display ...

  10. SQL Server如何将Id相同的字段合并,并且以逗号隔开

    需要用到stuff函数: 例: id             name           1               张三           1               李四       ...