【BZOJ4861】[Beijing2017]魔法咒语

题意:别看BZ的题面了,去看LOJ的题面吧~

题解:显然,数据范围明显的分成了两部分:一个是L很小,每个基本词汇长度未知;一个是L很大,每个基本词汇的长度是1或2。看来只能写两份代码了。

对于L很小的,我们先将禁忌串建成一个AC自动机,然后预处理出to[i][j]表示AC自动机中的第i个节点在加入基本词汇j后会到达的节点。然后设f[i][j]表示总长度为i,匹配到第j个节点的方案数。然后DP一下就好了。

对于L很大的,我们想到矩乘,设ans[i][j]表示总长度为i,匹配到第j个节点的方案数。但是ans[i]这个矩阵由ans[i-1]和ans[i-2]两个矩阵转移过来,所以我们直接用分块矩阵的乘法,即:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
int n,m,N,M,L,mx,sum;
struct mat
{
ll v[210][210];
mat (){memset(v,0,sizeof(v));}
ll* operator [](int a){return v[a];}
mat operator * (mat a)
{
mat ret;
int i,j,k;
for(i=1;i<=2*M;i++) for(j=1;j<=2*M;j++) for(k=1;k<=2*M;k++) (ret[i][j]+=v[i][k]*a[k][j])%=mod;
return ret;
}
}ans,x;
int l1[60],to[110][60];
ll f[110][110];
queue<int> q;
struct node
{
int ch[26],fail,cnt;
}p[110];
char s1[60][110],s2[60][110];
void build()
{
q.push(1);
int i,j,k,a,u;
while(!q.empty())
{
u=q.front(),q.pop();
for(i=0;i<26;i++)
{
if(!p[u].ch[i])
{
if(u==1) p[u].ch[i]=1;
else p[u].ch[i]=p[p[u].fail].ch[i];
continue;
}
q.push(p[u].ch[i]);
if(u==1)
{
p[p[u].ch[i]].fail=1;
continue;
}
p[p[u].ch[i]].fail=p[p[u].fail].ch[i];
p[p[u].ch[i]].cnt|=p[p[p[u].fail].ch[i]].cnt;
}
}
for(i=1;i<=M;i++) for(j=1;j<=n;j++)
{
u=i,a=strlen(s1[j]);
if(p[u].cnt) to[i][j]=-1;
for(k=0;k<a;k++)
{
u=p[u].ch[s1[j][k]-'a'];
if(p[u].cnt) break;
}
if(k==a) to[i][j]=u;
else to[i][j]=-1;
}
}
void DP()
{
int i,j,k,a;
f[0][1]=1;
for(i=0;i<L;i++) for(j=1;j<=M;j++) for(k=1;k<=n;k++)
{
if(to[j][k]==-1) continue;
a=strlen(s1[k]);
if(a+i<=L) (f[a+i][to[j][k]]+=f[i][j])%=mod;
}
for(i=1;i<=M;i++) sum=(sum+f[L][i])%mod;
printf("%d",sum);
}
void pm(int y)
{
while(y)
{
if(y&1) ans=ans*x;
x=x*x,y>>=1;
}
}
void MM()
{
int i,j;
for(i=1;i<=M;i++)
{
for(j=1;j<=n;j++)
{
if(to[i][j]==-1) continue;
if(strlen(s1[j])==1) x[i][to[i][j]]++;
else x[i+M][to[i][j]]++;
}
x[i][i+M]++;
}
ans[1][1]=1;
pm(L);
for(i=1;i<=M;i++) sum=(sum+ans[1][i])%mod;
printf("%d",sum);
}
int main()
{
scanf("%d%d%d",&n,&m,&L);
int i,j,a,b,u;
N=1,M=1;
for(i=1;i<=n;i++) scanf("%s",s1[i]),a=strlen(s1[i]),mx=max(mx,a);
for(i=1;i<=m;i++)
{
scanf("%s",s2[i]),a=strlen(s2[i]);
for(u=1,j=0;j<a;j++)
{
b=s2[i][j]-'a';
if(!p[u].ch[b]) p[u].ch[b]=++M;
u=p[u].ch[b];
}
p[u].cnt=1;
}
build();
if(mx<=2) MM();
else DP();
return 0;
}

【BZOJ4861】[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP的更多相关文章

  1. poj2778 矩阵乘法+ac自动机

    题:http://poj.org/problem?id=2778 题意:给定m个模式串,问长度为n的字符串不包含这些模式串的有几种可能 分析:因为n很大,所以考虑矩阵ksm来解决,构造一个矩阵res[ ...

  2. 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂

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

  3. BZOJ4861 [Beijing2017]魔法咒语

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

  4. 2021.11.11 P4052 [JSOI2007]文本生成器(AC自动机+DP)

    2021.11.11 P4052 [JSOI2007]文本生成器(AC自动机+DP) https://www.luogu.com.cn/problem/P4052 题意: JSOI 交给队员 ZYX ...

  5. 洛谷P4052 [JSOI2007]文本生成器 AC自动机+dp

    正解:AC自动机+dp 解题报告: 传送门! 感觉AC自动机套dp的题还挺套路的,,, 一般就先跑遍AC自动机,然后就用dp dp的状态一般都是f[i][j]:有i个字符,是ac自动机上的第j个节点, ...

  6. 对AC自动机+DP题的一些汇总与一丝总结 (2)

    POJ 2778 DNA Sequence (1)题意 : 给出m个病毒串,问你由ATGC构成的长度为 n 且不包含这些病毒串的个数有多少个 关键字眼:不包含,个数,长度 DP[i][j] : 表示长 ...

  7. POJ1625 Censored!(AC自动机+DP)

    题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...

  8. HDU2296 Ring(AC自动机+DP)

    题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...

  9. HDU2457 DNA repair(AC自动机+DP)

    题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...

随机推荐

  1. 四、Ubuntu 一些常用命令

    1.锁定root用户 :sudo passwd -l root 2.解锁root用户 :sudo passwd -u root 3.切换身份:su root  或者  su 其他用户名,然后输入密码, ...

  2. 大型网站优化-memcache技术

    大型网站优化-memcache技术 memory+cache 内存缓存 memcache简介 memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发 ...

  3. python画直线

    #!/usr/bin/env python import matplotlib.pyplot as plt import numpy as np #beita = 1 #gama = 0.5 #x:f ...

  4. CSS定位与布局:浮动

    浮动的特点   浮动(float)属性提出的作用是实现文字的环绕效果,一个元素浮动后,会脱离普通流.主要的特点如下: 浮动的元素会向左或者向右移动直到它的外边缘接触容器框(containing blo ...

  5. winform Loading效果

    做winform项目时,有可能用到异步耗时加载数据啥的,这个时候就需要我们封装一个正在加载的效果.下面是实现思路: 步骤一:把当前form界面使用句柄的方式截图出一个图片,这个图片会在下面用到,使用句 ...

  6. 执行sudo命令时的提示语,如何修改?

    如图所示,执行sudo命令,提示语(有中文和英文两个版本): 上面的提示内容是sudo软件原生的内容. 使用下面的方法,有的时候是可行的.sudo -p '提示语' 命令 如果要修改sudo软件原生的 ...

  7. ADO.NET-temple

    ylbtech-ADO.NET:ADO.NET-Oracle|SQLServer|MySql|Access|Excel-dddd 介绍及讲解 1.A,插入数据(Create) 1.B,读取数据(Rea ...

  8. poor-pigs(非常好的思路)

    https://leetcode.com/problems/poor-pigs/ package com.company; class Solution { // 下面第二种做法貌似是OJ原来的做法, ...

  9. [Django]中建立数据库视图

    Django中建立数据库视图 Django中没有建立视图的接口.假设要建立一个视图须要一些手动的改变. 这里使用的Django 版本号>1.5, 使用的数据库为mysql 第一步 建立视图,比如 ...

  10. OpenCV生成点集的Delaunay剖分和Voronoi图

    实现内容: 设置一副图像大小为600*600.图像像素值全为0,为黑色. 在图像中Rect(100,100,400,400)的区域随机产生20个点.并画出. 产生这些点集的Delaunay剖分和Vor ...