【BJOI2017】魔法咒语

2024-04-16 13:18
文章标签 魔法 咒语 bjoi2017

本文主要是介绍【BJOI2017】魔法咒语,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

时间限制 : 1000 MS 空间限制 : 131072 KB

问题描述

Chandra 是一个魔法天才。
从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术。这也多亏 Chandra有着常人难以企及的语言天赋,让她能轻松流利地说出咒语中那些极其拗口的魔法词汇。

直到十四岁,开始学习威力强大的禁咒法术时,Chandra 才遇到了障碍。

根据火之魔法规则,禁咒的构成单位是 N 个基本词汇。施法时只要凝聚精神力,说出一段用这些词语组成的长度恰好等于 L 的语言,就能释放威力超乎想象的火法术。过去的魔法师们总结了几种表达起来最连贯的组合方式,方便施法者以最快语速完成法术。

但具有魔法和语言双重天才的 Chandra不满足于这几种流传下来的禁咒,因为她可以毫无困难地说出普通人几乎不可能表达的禁咒语句。然而,在实际施法时,Chandra 发现有些自创禁咒念出后不但没有预期效果,反而会使自己的精神力迅速枯竭,十分难受。

这个问题令 Chandra 万分不解。她大量阅读典籍,到处走访魔法学者,并且不顾精神折磨一次又一次尝试新咒语,希望找出问题的答案。

很多年过去了,在一次远古遗迹探险中,Chandra意外闯进了火之神艾利克斯的不知名神殿。根据岩土特征分析,神殿应该有上万年的历史,这是极其罕见的。Chandra 小心翼翼地四处探索,沿着魔力流动来到一间密室。她看见密室中央悬浮着一本书籍。在魔法保护下书籍状况完好。精通上古语言的 Chandra 读过此书,终于解开了多年的困惑。

禁咒法术之所以威力强大,是因为咒语借用了火之神艾利克斯的神力。这本书里记载了艾利克斯生平忌讳的 M 个词语,比如情敌的名字、讨厌的植物等等。使用禁咒法术时,如果语言中含有任何忌讳词语,就会触怒神力而失效,施法者也一并遭受惩罚。

例如,若 ”banana” 是唯一的忌讳词语,“an”、”ban”、”analysis” 是基本词汇,禁咒长度须是11,则“bananalysis” 是无效法术,”analysisban”、”anbanbanban”是两个有效法术。注意:一个基本词汇在禁咒法术中可以出现零次、一次或多次;只要组成方式不同就认为是不同的禁咒法术,即使书写形式相同。

谜题破解,Chandra 心情大好。她决定计算一共有多少种有效的禁咒法术。

由于答案可能很大,你只需要输出答案模 1,000,000,007 的结果。

输入格式

第一行,三个正整数 N, M, L。
接下来 N 行,每行一个只含小写英文字母的字符串,表示一个基本词汇。
接下来 M 行,每行一个只含小写英文字母的字符串,表示一个忌讳词语。

输出格式

仅一行,一个整数,表示答案(模 10^9+7)。

样例输入 1

4 2 10
boom
oo
ooh
bang
ob
mo

样例输出 1

14

样例输入 2

3 1 3
a
ab
aba
aaa

样例输出 2

3

样例输入 3

3 1 14
ban
an
analysis
banana

样例输出 3

15

提示

样例解释 1】

有效的禁咒法术共有 14 种:boom/bang/oo,oo/oo/oo/oo/oo,oo/oo/ooh/ooh,

oo/ooh/oo/ooh,oo/ooh/ooh/oo,ooh/oo/oo/ooh,ooh/oo/ooh/oo,

ooh/ooh/boom,ooh/ooh/oo/oo,ooh/ooh/bang,ooh/bang/ooh,

bang/oo/oo/oo,bang/ooh/ooh,bang/bang/oo。

【样例解释 2】

有效的禁咒法术有 a/ab, ab/a, aba 共三种。注意,ab/a 和 aba 算成两种不同的禁咒法术。

【数据规模与约定】

本题一共有 10 个测试点。

下表是每个测试点的数据规模和约定:
这里写图片描述

题解

题目描述有点长,看起来比较吓人,但题意还是比较简单的。
对于前60%的数据,直接对忌讳词语建AC自动机,然后在机子上跑记忆化搜索或递推就可以了。
本题主要难点在后40%,尤其是最后20%的数据上。我们可以把AC自动机看成一张图,在字符串后接上某基本词语就相当于从图上一点走一条路径到达另一点。观察数据的特殊性——基本词语长度为1或2且 L L 很大。如果所有基本词语长度都只有1,那么在图上的转移路径就只会经过一条边,题目问题就转化为了已知图上两点间有一条边,求从起点(AC自动机根节点)出发走L条边后在任意点停下的方案数——经典的矩阵乘法问题!要处理禁忌词汇,只需提前预处理出所有路径的起止点,当终点为某禁忌词汇的末尾时,删去该路径即可。对于基本词语长度为2的情况,我们需要构造虚拟点在原路径的起止点间做中转,相当于起点到终点需走两步(经过两条边),注意最后计算结果时不能包含虚拟点!
为什么前60%的数据不能用后40%的方法?基础词汇太长->虚拟点太多->时空复杂度爆炸!
详见代码……

代码

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef ll arr[205][205];
const ll mod=1e9+7;
ll n,m,l,tot,val[105],fail[105],trie[105][30],G[105][55];
ll N,ans,f[105][105];
arr I,A;
char c[55][105],tab[105];
queue<ll> q;
namespace ACAM
{void Insert(){ll p=0,len=strlen(tab+1);for(ll i=1;i<=len;i++){ll t=tab[i]-'a';if(!trie[p][t]) trie[p][t]=++tot;p=trie[p][t];}val[p]++;}void Getfail(){for(ll i=0;i<26;i++)if(trie[0][i]) q.push(trie[0][i]);while(!q.empty()){ll x=q.front();q.pop();for(ll i=0;i<26;i++){ll son=trie[x][i];if(!son){trie[x][i]=trie[fail[x]][i];continue;}q.push(son);ll y=fail[x];while(y&&!trie[y][i]) y=fail[y];fail[son]=trie[y][i],val[son]|=val[fail[son]];}}}ll Goto(ll p,ll x){ll len=strlen(c[x]+1);for(ll i=1;i<=len;i++)if(!val[trie[p][c[x][i]-'a']]) p=trie[p][c[x][i]-'a'];else return -1;return p;}ll DFS(ll p,ll step){if(step==l) return 1;if(~f[p][step]) return f[p][step];f[p][step]=0;for(ll i=1;i<=n;i++)if((~G[p][i])&&step+strlen(c[i]+1)<=l)f[p][step]=(f[p][step]+DFS(G[p][i],step+strlen(c[i]+1)))%mod;return f[p][step];}
}
namespace matrix
{void mul(arr y,arr x){arr z;memset(z,0,sizeof(z));for(ll i=0;i<=N;i++)for(ll j=0;j<=N;j++)for(ll k=0;k<=N;k++)z[i][j]=(z[i][j]+y[i][k]*x[k][j]%mod)%mod;memcpy(y,z,sizeof(z));}void ksm(ll b){for(ll i=0;i<=N;i++) I[i][i]=1;while(b){if(b&1) mul(I,A);b>>=1;mul(A,A);}}
}
int main()
{scanf("%lld%lld%lld",&n,&m,&l);for(ll i=1;i<=n;i++) scanf("%s",c[i]+1);for(ll i=1;i<=m;i++) scanf("%s",tab+1),ACAM::Insert();ACAM::Getfail();for(ll i=0;i<=tot;i++)for(ll j=1;j<=n;j++) G[i][j]=ACAM::Goto(i,j);if(l<=100){memset(f,-1,sizeof(f));ACAM::DFS(0,0);printf("%lld\n",f[0][0]);}else{N=2*tot+1;for(ll i=0;i<=tot;A[i][i+tot+1]++,i++)for(ll j=1;j<=n;j++)if(~G[i][j])if(strlen(c[j]+1)==1) A[i][G[i][j]]++;else A[i+tot+1][G[i][j]]++;matrix::ksm(l);for(ll i=0;i<=tot;i++) ans=(ans+I[0][i])%mod;printf("%lld\n",ans);}return 0;
}

这篇关于【BJOI2017】魔法咒语的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908889

相关文章

def __init__ python特殊方法(也称为魔法方法或双下划线方法)

这些特殊方法(也称为魔法方法或双下划线方法)是由 Python 的数据模型(data model)规定的,用于定义对象的行为。它们通常用于实现内置操作和函数的行为,如算术运算、比较操作、容器类型(如列表和字典)的行为等。 特殊方法的命名规定 这些方法的名字都是由 Python 语言规范规定的,以下是一些常见的特殊方法及其用途: 对象表示 __str__(self):定义当使用 str()

Python协程探秘:async/await的魔法

Python协程探秘:async/await的魔法 在Python的并发编程世界中,协程(Coroutines)和async/await关键字正逐渐崭露头角,它们提供了一种高效、轻量级的并发解决方案。本文将深入解释协程的概念,探讨async/await关键字的作用,并通过示例展示如何在Python中使用它们。 一、协程简介 协程,又称为微线程(Microthreads)或用户态线程(User

从WebM到MP3:利用Python和wxPython提取音乐的魔法

前言 有没有遇到过这样的问题:你有一个包含多首歌曲的WebM视频文件,但你只想提取其中的每一首歌曲,并将它们保存为单独的MP3文件?这听起来可能有些复杂,但借助Python和几个强大的库,这个任务变得异常简单。今天,我将带你一步步实现这个小工具,并且给它取个有趣的名字:“魔法音乐分离器”。 C:\pythoncode\new\splitsongfromwebmintomp3.py 准备工作

MathType软件2024永久免费版下载!数学公式的魔法棒

【MathType软件:数学公式的魔法棒】 大家好👋,今天我要和大家分享一个我最近发现的学习神器——MathType软件!这是一款专门用于编辑数学公式的软件,功能强大到让我惊叹不已!🌟 MathType最新Win官方版本下载如下: https://wm.makeding.com/iclk/?zoneid=34223 MathType最新Mac官方版本下载如下: https://wm.m

帕金森病友也能享用的“魔法水果”:营养与健康的双重守护

帕金森病,这个听起来有些陌生的名词,如今却越来越频繁地出现在我们的生活中。作为一种慢性神经系统疾病,帕金森病给患者的日常生活带来了诸多不便。然而,你知道吗?除了药物治疗和康复训练,日常生活中的饮食也能成为帕金森病友的“健康助手”。今天,就让我们一起探索那些对帕金森病患者有益的“魔法水果”,看看它们如何成为营养与健康的双重守护。 首先,我们要了解的是苹果。苹果富含抗氧化物质和维生素C,这些成分

揭秘沟通之谜:自然语言处理(NLP)的魔法世界

自然语言处理NLP 一、引言1.1 定义自然语言处理(NLP)及其重要性1.2 NLP在人工智能领域的地位和作用 二、历史发展2.1 NLP的起源和历史演变2.2 关键技术突破和发展历程2.3 当前NLP的发展趋势和未来展望 三、NLP的主要技术和应用3.1 语言模型3.2 句法分析3.3 语义分析3.4 机器翻译3.5 语音识别与合成3.6 情感分析3.7 信息提取和文本挖掘 四、NLP面

Shell编程练习:掌握命令行的魔法

1、编写一个 shell 脚本,它把第二个位置参数及其以后的各个参数指定的文件复制到第一个位置参数指定的目录中。 #!/bin/bash# 检查是否提供了至少两个参数if [ "$#" -lt 2 ]; thenecho "使用方法: $0 目标目录 文件..."exit 1fi# 第一个位置参数是目标目录DEST_DIR="$1"# 移除第一个参数,剩下的都是文件shift# 创建

试试Python的__slots__魔法,再也不用担心内存不够用了!

目录 1、初始之解:__slots__基础运用 1.1 __slots__魔法简介 1.2 如何节省内存空间 1.3 实战示例:类定义与性能对比 2、进阶篇:结合元类深化理解 🧠 2.1 元类回顾与应用 2.2 动态管理__slots__ 2.3 高级技巧:动态添加属性 2.4 __slots__与@property装饰器 3、深入探索:__slots__限制与规避 🕵

文字炫酷祝福 含魔法代码

效果下图:(可自定义显示内容) 代码如下: <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>body {font-f

位运算算法:编程世界中的魔法符号

✨✨✨学习的道路很枯燥,希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一. 常见位运算总结 二、常见位运算题目 2.1 位1的个数 2.2 比特数记位(典型dp)  2.3 汉明距离 2.4 只出现一次的数字(1)  2.5 只出现一次的数字(2)    2.6 只出现一次的数字(3)  2.7  判断字符是否为1 2.8 丢失的数字  2.