【题意】给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量。(60%)n,m<=50,L<=100。(40%)原串长度为1或2,L<=10^18。

【算法】AC自动机+DP+矩阵快速幂

【题解】其实题意的数据范围不太清晰,反正开200个点就足够了。

因为要匹配禁忌串,所以对禁忌串集合建立AC自动机,标记禁忌串结尾节点,以及下传到所有能fail到的点(这些点访问到都相当于匹配了禁忌串)。

令f[i][j]表示匹配到节点i,长度为j的串的数量,先预处理a[i][j]表示节点 i 匹配第 j 个原串到达的节点编号,那么就有:

f [ a[i][j] ] [ L+size[j] ] += f [ i ] [ L ]

以上就是60%数据的做法,对于40%的数据使用矩阵快速幂。

假设原串长度均为1,那么DP的转移如下:

$$f[i][L]=\sum_{j}f[j][L-1]\ \ ,\ \ j \rightarrow i$$

这很容易用一个长度为第一维大小(AC自动机节点数)的矩阵维护转移,第L个列向量就是f[i][L]。

如果原串长度有2,那么再记录L-1即可。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=,MOD=1e9+;
int n,m,a[maxn][],ch[maxn][],val[maxn],size[maxn],sz=,fail[maxn];
ll L;
char s[][maxn],S[maxn];
queue<int>Q;
void insert(char *s){
int n=strlen(s),u=;
for(int i=;i<n;i++){
int c=s[i]-'a';
if(!ch[u][c])ch[u][c]=++sz;
u=ch[u][c];
}
val[u]++;
}
void AC_build(){
for(int c=;c<;c++)if(ch[][c])Q.push(ch[][c]);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int c=;c<;c++)if(ch[u][c]){
fail[ch[u][c]]=ch[fail[u]][c];
Q.push(ch[u][c]);
val[ch[u][c]]|=val[fail[ch[u][c]]];//
}
else ch[u][c]=ch[fail[u]][c];
}
}
int M(int x){return x>=MOD?x-MOD:x;}
namespace Task1{
int f[maxn][];
void solve(){
f[][]=;
for(int l=;l<L;l++){//
for(int i=;i<=sz;i++)if(f[i][l]){
for(int j=;j<=n;j++)if(~a[i][j]&&l+size[j]<=L){
f[a[i][j]][l+size[j]]=M(f[a[i][j]][l+size[j]]+f[i][l]);
}
}
}
int ans=;
for(int i=;i<=sz;i++)if(f[i][L]&&!val[i])ans=M(ans+f[i][L]);
printf("%d",ans);
}
}
namespace Task2{
const int maxn=;
int N,A[maxn*][maxn*],ANS[maxn*][maxn*],c[maxn*][maxn*];
void mul(int a[maxn*][maxn*],int b[maxn*][maxn*]){
for(int i=;i<=N;i++){
for(int j=;j<=N;j++){
c[i][j]=;
for(int k=;k<=N;k++)c[i][j]=M(c[i][j]+1ll*a[i][k]*b[k][j]%MOD);
}
}
for(int i=;i<=N;i++)for(int j=;j<=N;j++)b[i][j]=c[i][j];
}
void solve(){
N=sz*+;
for(int i=;i<=sz;i++){
for(int j=;j<=n;j++)if(~a[i][j]){
if(size[j]==)A[a[i][j]*][i*]++;
else A[a[i][j]*][i*+]++;
}
A[i*+][i*]=;
}
ANS[][]=;
while(L){
if(L&)mul(A,ANS);
mul(A,A);
L>>=;
}
int ans=;
for(int i=;i<=sz;i++)if(!val[i])ans=M(ans+ANS[i*][]);
printf("%d",ans);
}
}
int main(){
scanf("%d%d%lld",&n,&m,&L);
for(int i=;i<=n;i++)scanf("%s",s[i]);
for(int i=;i<=m;i++){
scanf("%s",S);
insert(S);
}
AC_build();
memset(a,-,sizeof(a));
for(int k=;k<=n;k++){
size[k]=strlen(s[k]);
for(int i=;i<=sz;i++){
int u=i;
for(int j=;j<size[k];j++)if(!val[u])u=ch[u][s[k][j]-'a'];else break;
if(!val[u])a[i][k]=u;
}
}
if(L<=)Task1::solve();else
Task2::solve();
return ;
}

【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂的更多相关文章

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

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

  2. 【BZOJ】2553: [BeiJing2011]禁忌 AC自动机+期望+矩阵快速幂

    [题意]给定n个禁忌字符串和字符集大小alphabet,保证所有字符在集合内.一个字符串的禁忌伤害定义为分割能匹配到最多的禁忌字符串数量(一个可以匹配多次),求由字符集构成的长度为Len的字符串的期望 ...

  3. BZOJ2553 Beijing2011禁忌(AC自动机+动态规划+矩阵快速幂+概率期望)

    考虑对一个串如何分割能取得最大值.那么这是一个经典的线段覆盖问题,显然每次取右端点尽量靠前的串.于是可以把串放在AC自动机上跑,找到一个合法串后就记录并跳到根. 然后考虑dp.设f[i][j]表示前i ...

  4. BZOJ 2004 公交线路(状压DP+矩阵快速幂)

    注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压. 然后状压DP一下,用矩阵快速幂加速运算即可. #include <stdio.h> #include ...

  5. BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)

    题目链接 先考虑 假设S确定,使构造S操作次数最小的方案应是:对T建SAM,S在SAM上匹配,如果有S的转移就转移,否则操作数++,回到根节点继续匹配S.即每次操作一定是一次极大匹配. 简单证明:假设 ...

  6. bzoj 1898: [Zjoi2005]Swamp 沼泽鳄鱼【dp+矩阵快速幂】

    注意到周期234的lcm只有12,也就是以12为周期,可以走的状态是一样的 所以先预处理出这12个状态的转移矩阵,乘起来,然后矩阵快速幂优化转移k/12次,然后剩下的次数暴力转移即可 #include ...

  7. bzoj 2326: [HNOI2011]数学作业【dp+矩阵快速幂】

    矩阵乘法一般不满足交换律!!所以快速幂里需要注意乘的顺序!! 其实不难,设f[i]为i的答案,那么f[i]=(f[i-1]w[i]+i)%mod,w[i]是1e(i的位数),这个很容易写成矩阵的形式, ...

  8. [poj2778 DNA Sequence]AC自动机,矩阵快速幂

    题意:给一些字符串的集合S和整数n,求满足 长度为n 只含charset = {'A'.'T‘.'G'.'C'}包含的字符 不包含S中任一字符串 的字符串的种类数. 思路:首先对S建立ac自动机,考虑 ...

  9. BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

    状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...

随机推荐

  1. spark作用流程

    原文:https://www.cnblogs.com/asura7969/p/8441471.html https://blog.csdn.net/xu__cg/article/details/700 ...

  2. 一次WebSphere性能问题诊断过程

    一次接到用户电话,说某个应用在并发量稍大的情况下就会出现响应时间陡然增大,同时管理控制台的响应时间也很慢,几乎无法进行正常工作. 赶到现场后,查看平台版本为Webshpere6.0.2.29,操作系统 ...

  3. ant 安装及基础教程 !

    这篇文章主要介绍了ant使用指南详细入门教程,本文详细的讲解了安装.验证安装.使用方法.使用实例.ant命令等内容,需要的朋友可以参考下   一.概述 ant 是一个将软件编译.测试.部署等步骤联系在 ...

  4. linux应用自启动配置

    Linux在启动时,会自动执行/etc/rc.d目录下的初始化程序,因此我们可以把启动任务放到该目录下: 1.因为其中的rc.local是在完成所有初始化之后执行,因此可以把启动脚本写到里面: 2.用 ...

  5. puppeteer设置代理并检查代理是否设置成功

    1. 设置代理: 这一步超级简单,但我掉到了坑里并扑腾了小一天的时间,那就是:箭头指向处一定一定不要加空格!!! 2. 检查代理是否设置成功: 在打开的浏览器里,打开百度,输入ip,如果查出来的结果跟 ...

  6. 'phantomjs.exe' executable needs to be in PATH. (selenium PhantomJS python)

    今天selenium PhantomJS python用了下,发现报错,提示我:'phantomjs.exe' executable needs to be in PATH. from seleniu ...

  7. SQL优化套路

    直奔主题: (1) SELECT(2) DISTINCT <SELECT_LIST>(3) FROM <LEFT_TABLE> <JOIN_TYPE> (4) JO ...

  8. centos中apache自用常用额外配置记录(xwamp)

    xwamp套件中apache配置,记录下,以免忘记. 配置路径 ${wwwroot_dir}/conf/httpd.conf 配置内容 <ifmodule mod_deflate.c> D ...

  9. 第146天:移动H5前端性能优化

    移动H5前端性能优化 一.概述 1. PC优化手段在Mobile侧同样适用 2. 在Mobile侧我们提出三秒种渲染完成首屏指标 3. 基于第二点,首屏加载3秒完成或使用Loading 4. 基于联通 ...

  10. 第119天:移动端:CSS像素、屏幕像素和视口的关系

    移动前端中常说的 viewport (视口)就是浏览器显示页面内容的屏幕区域.其中涉及几个重要概念是 dip ( device-independent pixel 设备逻辑像素 )和 CSS 像素之间 ...