bzoj4861 / P3715 [BJOI2017]魔法咒语
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]魔法咒语相关推荐
- P3715 [BJOI2017]魔法咒语
P3715 [BJOI2017]魔法咒语 用基本词汇组成\(L\)长度的单词,其中不能包含禁忌词汇 用禁忌词汇建强大的\(tire\)图 解决: 分类讨论,\(L<=100\)用普通dp暴力在\ ...
- 【BZOJ4861】[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP
[BZOJ4861][Beijing2017]魔法咒语 题意:别看BZ的题面了,去看LOJ的题面吧~ 题解:显然,数据范围明显的分成了两部分:一个是L很小,每个基本词汇长度未知:一个是L很大,每个基本 ...
- BJOI2017 魔法咒语
传送门 参考博客 l ⩽ 100 l \leqslant100 l⩽100的 d p dp dp很好做. 对于 l ⩽ 1 e 8 l \leqslant 1e8 l⩽1e8,由于有基本词汇长度不超过 ...
- 【[BJOI2017]魔法咒语】
矩阵乘法+\(AC\)自动机 是道很不错的题了 首先是前六十分,就是一个\(AC\)自动机上的套路\(dp\),设\(dp[i][j]\)表示匹配出的长度为\(i\)在自动机上位置为\(j\)的方案数 ...
- [BJOI2017]魔法咒语(AC自动机+DP+矩阵快速幂)
文章目录 title solution code title solution 针对数据编程才是坠吊的!!! 观察数据,发现分隔数据的 L L L跨度过大,没有衔接--推测很有可能是分数据做法 ①:考 ...
- 【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显然是不行的 但是发现 ...
- [bzoj4861]魔法咒语
题目描述 瞎做 显然是AC自动机dp. 小的直接dp大的矩阵乘法. #include<cstdio> #include<algorithm> #include<cstri ...
- 【AC自动机】【矩阵加速】BZOJ4861魔法咒语
分析: 巨恶心的一题双代码题. 对于前半部分,把禁止出现的字符串建一颗AC自动机. 然后枚举每个位置用了某个模板串后转移到哪里. 然后直接DP即可. 但是对于后半部分数据,则必须写一个矩阵加速... ...
- BZOJ4861 魔法咒语 【AC自动机】【DP】【矩阵快速幂】
题意: 用n个基本词汇拼出长度为L的字符串,每个基本词汇可以用0次,1次或多次,要求拼出的字符串不能出现m个禁忌词汇中的任何一个,求方案数 mod 1e9+7 60% :1<=N,M<=5 ...
最新文章
- 网址服务器地址修改,网址服务器地址修改
- 团队-Forward团队一阶段互评
- Apk文件结构, Dex反编译
- .NET Core 容器化调查
- comment desc显示表结构_MySQL 查看表结构简单命令
- 带有HttpClient的自定义HTTP标头
- 信安精品课:2020年软考信息安全工程师备考公开课
- 编辑器Ultraedit快捷键
- Android Service 的重启
- 模板题——单链表双链表,数组模拟的栈和队列,单调栈和单调队列
- cakephp index.php,CakePHP - 中文手册
- 高考476分在浙江计算机学院,2021年高考476分左右能上什么大学(100所)
- windows下Git连接使用
- EagleEye:一种用模型剪枝的快速衡量子网络性能的方法
- html检测正则表达式,正则表达式在线测试工具
- 成都可以打狂犬疫苗的地方
- 【安卓】电脑执行脚本控制安卓手机
- 杭州旭航集团,申请纳斯达克IPO上市,募资9800万美元
- [转载/精华]JAVA中文显示乱码的原因
- Tomcat启动报错-failed setting ip_ttl
热门文章
- 用强化学习DQN算法玩合成大西瓜游戏!(提供Keras版本和Paddlepaddle版本)
- spring事务——try{...}catch{...}中事务不回滚的几种处理方式
- 《如果我们生来不会流泪》那就让诗歌来浸润~
- android导入win10照片,iphone手机照片导入win10电脑的方法
- Android KitKat
- 数据中台与数据平台的关系
- Golang 中 Slice的分析与使用(含源码)
- 三端一体计算方案:Unify SQL Engine
- Go 语言圣经 7.4 flag.Value接口
- mysql查询所有男生信息_MySQL 数据查询