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开始

(为啥我的常数这么大呢......)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 using namespace std;
 6 #define N 105
 7 const int mod=1e9+7;
 8 int ans,sz,n,m,L,siz[N],f[N][N],p[N][N];
 9 char q[N],s[N][N];
10 queue <int> h;
11
12 struct node{int nxt[26],f,ed;}a[5002];
13 void add(){
14     scanf("%s",q);
15     int len=strlen(q),u=0;
16     for(int i=0;i<len;++i){
17         if(!a[u].nxt[q[i]-'a'])
18             a[u].nxt[q[i]-'a']=++sz;
19         u=a[u].nxt[q[i]-'a'];
20     }a[u].ed=1;
21 }
22 void acbuild(){
23     for(int i=0;i<26;++i) if(a[0].nxt[i]) h.push(a[0].nxt[i]);
24     while(!h.empty()){
25         int x=h.front();h.pop();
26         for(int i=0;i<26;++i){
27             int &to=a[x].nxt[i];
28             if(to){
29                 a[to].f=a[a[x].f].nxt[i];
30                 a[to].ed|=a[a[to].f].ed;
31                 h.push(to);
32             }else to=a[a[x].f].nxt[i];
33         }
34     }
35 }
36
37 struct mat{
38     int A[205][205];
39     mat(){memset(A,0,sizeof(A));}
40     mat operator * (mat &tmp) const{
41         mat c;int w=sz<<1|1;
42         for(int i=0;i<=w;++i)
43             for(int j=0;j<=w;++j)
44                 for(int k=0;k<=w;++k)
45                     c.A[i][j]=(c.A[i][j]+1ll*A[i][k]*tmp.A[k][j]%mod)%mod;
46         return c;
47     }
48 };
49 mat Pow(mat x,int y){
50     mat rs;
51     for(int i=0;i<=sz;++i)
52         rs.A[i<<1][i<<1]=1;
53     for(;y;y>>=1,x=x*x)
54         if(y&1) rs=rs*x;
55     return rs;
56 }
57
58 void task1(){
59     f[0][0]=1;
60     for(int i=0;i<L;++i)
61         for(int j=0;j<=sz;++j)
62             if(f[j][i])
63                 for(int k=1;k<=n;++k)
64                     if(p[j][k]!=-1&&i+siz[k]<=L)
65                             f[p[j][k]][i+siz[k]]=(f[p[j][k]][i+siz[k]]+f[j][i])%mod;
66     for(int i=0;i<=sz;++i) if(!a[i].ed) ans=(ans+f[i][L])%mod;
67 }
68 void task2(){
69     mat res;
70     for(int i=0;i<=sz;++i){
71         for(int j=1;j<=n;++j)
72             if(p[i][j]!=-1){
73                 if(siz[j]==1) ++res.A[p[i][j]<<1][i<<1];
74                 else ++res.A[p[i][j]<<1][i<<1|1];
75             }
76         res.A[i<<1|1][i<<1]=1;
77     }res=Pow(res,L);
78     for(int i=0;i<=sz;++i) if(!a[i].ed) ans=(ans+res.A[i<<1][0])%mod;
79 }
80 int main(){
81     memset(p,-1,sizeof(p));
82     scanf("%d%d%d",&n,&m,&L);
83     for(int i=1;i<=n;++i) scanf("%s",s[i]),siz[i]=strlen(s[i]);
84     for(int i=1;i<=m;++i) add();
85     acbuild();
86     for(int i=1;i<=n;++i)
87         for(int j=0,u=0;j<=sz;u=++j){
88             for(int k=0;k<siz[i]&&!a[u].ed;++k)
89                 u=a[u].nxt[s[i][k]-'a'];
90             if(!a[u].ed) p[j][i]=u;
91         }
92     if(L<=100) task1();
93     else task2();
94     printf("%d",ans);
95     return 0;
96 }

View Code

转载于:https://www.cnblogs.com/kafuuchino/p/10193188.html

bzoj4861 / P3715 [BJOI2017]魔法咒语相关推荐

  1. P3715 [BJOI2017]魔法咒语

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

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

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

  3. BJOI2017 魔法咒语

    传送门 参考博客 l ⩽ 100 l \leqslant100 l⩽100的 d p dp dp很好做. 对于 l ⩽ 1 e 8 l \leqslant 1e8 l⩽1e8,由于有基本词汇长度不超过 ...

  4. 【[BJOI2017]魔法咒语】

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

  5. [BJOI2017]魔法咒语(AC自动机+DP+矩阵快速幂)

    文章目录 title solution code title solution 针对数据编程才是坠吊的!!! 观察数据,发现分隔数据的 L L L跨度过大,没有衔接--推测很有可能是分数据做法 ①:考 ...

  6. 【BZOJ4861】【BJOI2017】—魔法咒语(AC自动机+矩阵快速幂优化dp)

    传送门 当 l ≤ 100 l\le 100 l≤100时 显然的自动机上 d p dp dp就完了 当 l ≤ 1 e 8 l\le1e8 l≤1e8时直接 d p dp dp显然是不行的 但是发现 ...

  7. [bzoj4861]魔法咒语

    题目描述 瞎做 显然是AC自动机dp. 小的直接dp大的矩阵乘法. #include<cstdio> #include<algorithm> #include<cstri ...

  8. 【AC自动机】【矩阵加速】BZOJ4861魔法咒语

    分析: 巨恶心的一题双代码题. 对于前半部分,把禁止出现的字符串建一颗AC自动机. 然后枚举每个位置用了某个模板串后转移到哪里. 然后直接DP即可. 但是对于后半部分数据,则必须写一个矩阵加速... ...

  9. BZOJ4861 魔法咒语 【AC自动机】【DP】【矩阵快速幂】

    题意: 用n个基本词汇拼出长度为L的字符串,每个基本词汇可以用0次,1次或多次,要求拼出的字符串不能出现m个禁忌词汇中的任何一个,求方案数 mod 1e9+7 60% :1<=N,M<=5 ...

最新文章

  1. 网址服务器地址修改,网址服务器地址修改
  2. 团队-Forward团队一阶段互评
  3. Apk文件结构, Dex反编译
  4. .NET Core 容器化调查
  5. comment desc显示表结构_MySQL 查看表结构简单命令
  6. 带有HttpClient的自定义HTTP标头
  7. 信安精品课:2020年软考信息安全工程师备考公开课
  8. 编辑器Ultraedit快捷键
  9. Android Service 的重启
  10. 模板题——单链表双链表,数组模拟的栈和队列,单调栈和单调队列
  11. cakephp index.php,CakePHP - 中文手册
  12. 高考476分在浙江计算机学院,2021年高考476分左右能上什么大学(100所)
  13. windows下Git连接使用
  14. EagleEye:一种用模型剪枝的快速衡量子网络性能的方法
  15. html检测正则表达式,正则表达式在线测试工具
  16. 成都可以打狂犬疫苗的地方
  17. 【安卓】电脑执行脚本控制安卓手机
  18. 杭州旭航集团,申请纳斯达克IPO上市,募资9800万美元
  19. [转载/精华]JAVA中文显示乱码的原因
  20. Tomcat启动报错-failed setting ip_ttl

热门文章

  1. 用强化学习DQN算法玩合成大西瓜游戏!(提供Keras版本和Paddlepaddle版本)
  2. spring事务——try{...}catch{...}中事务不回滚的几种处理方式
  3. 《如果我们生来不会流泪》那就让诗歌来浸润~
  4. android导入win10照片,iphone手机照片导入win10电脑的方法
  5. Android KitKat
  6. 数据中台与数据平台的关系
  7. Golang 中 Slice的分析与使用(含源码)
  8. 三端一体计算方案:Unify SQL Engine
  9. Go 语言圣经 7.4 flag.Value接口
  10. mysql查询所有男生信息_MySQL 数据查询