题:http://poj.org/problem?id=2778

题意:给定m个模式串,问长度为n的字符串不包含这些模式串的有几种可能

分析:因为n很大,所以考虑矩阵ksm来解决,构造一个矩阵res[i][j]表示从i到j有多少种方案数,我们先考虑只走1步后的res数组的构造,i节点能走到j节点当且仅当i节点和j节点都是安全的点,这个安全的点就是用m个模式串构成的trie树上的end[],显然根结点是安全结点。 一个非根结点是危险结点的充要条件是: 它的路径字符串本身就是一个不良单词 ,或 它的路径字符串的后缀对应的结点(即fail[i])是危险结点。预处理完ac自动机后,就可以处理res数组,这个res数组就相当于在学离散数学时的矩阵;剩下的n步就交给ksm这个res数组即可,答案就是sum(res[0][i])

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=1e5;
const int maxn=;///只有4个字母
const int N=1e3+;
struct ac{
int trie[N][maxn],fail[N];
int tot,root;
bool end[N];
ll res[N][N],ans[N][N],tmp[N][N];
int newnode(){
for(int i=;i<maxn;i++){
trie[tot][i]=-;
}
end[tot++]=;
return tot-;
}
void init(){
tot=;
root=newnode();
memset(res,,sizeof(res));
memset(ans,,sizeof(ans));
memset(end,false,sizeof(end));
}
int getid(char c){
if(c=='A')
return ;
if(c=='C')
return ;
if(c=='T')
return ;
if(c=='G')
return ;
}
void insert(char *buf,int id){
int now=root,len=strlen(buf);
for(int i=;i<len;i++){
int x=getid(buf[i]);
if(trie[now][x]==-)
trie[now][x]=newnode();
now=trie[now][x];
}
end[now]=true;//它的路径字符串本身就是一个不良单词
}
void getfail(){ queue<int>que;
while(!que.empty())
que.pop();
fail[root]=root;
for(int i=;i<maxn;i++)
if(trie[root][i]==-)
trie[root][i]=root;
else{
fail[trie[root][i]]=root;
que.push(trie[root][i]);
}
while(!que.empty()){
int now=que.front();
que.pop();
if(end[fail[now]])//它的路径字符串的后缀对应的结点(即fail[i])是危险结点
end[now]=true;
for(int i=;i<maxn;i++){
if(trie[now][i]!=-){
fail[trie[now][i]]=trie[fail[now]][i];
que.push(trie[now][i]);
}
else
trie[now][i]=trie[fail[now]][i];
}
}
} void path(){
for(int i=;i<tot;i++){
for(int j=;j<maxn;j++)
if(!end[i]&&!end[trie[i][j]]){
// cout<<i<<"!!"<<j<<endl;
res[i][trie[i][j]]++;
} }
}
void mul(ll a[][N],ll b[][N]){
for(int i=;i<tot;i++)
for(int j=;j<tot;j++){
tmp[i][j]=;
for(int k=;k<tot;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
}
for(int i=;i<tot;i++)
for(int j=;j<tot;j++)
a[i][j]=tmp[i][j];
}
ll solve(int n){ for(int i=;i<tot;i++)
ans[i][i]=;
while(n){
if(n&){
mul(ans,res);
}
n>>=;
mul(res,res);
}
ll ANS=;
for(int i=;i<tot;i++)
ANS=(ANS+ans[][i])%mod;
return ANS;
}
}AC;
char s[];
int main(){
int m,n;
scanf("%d%d",&m,&n);
AC.init();
for(int i=;i<=m;i++){
scanf("%s",s);
AC.insert(s,i);
}
AC.getfail();
AC.path();
printf("%lld\n",AC.solve(n));
return ;
}

最新文章

  1. px、dp与sp的区别以及换算
  2. asp.net mvc 之旅—— 第二站 窥探Controller下的各种Result
  3. What he did
  4. (转) java 简单工厂模式(实现一个计算器)
  5. Oracle中常用操作
  6. 我的总结SVN的使用
  7. 实时数据处理环境搭建flume+kafka+storm:2.flume 安装
  8. jQuery树叶掉落特效代码
  9. bzoj1643 [Usaco2007 Oct]Bessie&#39;s Secret Pasture 贝茜的秘密草坪
  10. centOS6 php 编 imap 模
  11. Redis字符串类型相关操作命令
  12. thinkphp的model模型的设计经验总结
  13. appium+Android studio安装与配置
  14. mxgraph进阶(二)mxgraph的初步介绍与开发入门
  15. FFmpeg 结构体学习(六): AVCodecContext 分析
  16. Sqlserver 计算两坐标距离函数
  17. js获取复选框值
  18. Java的隐秘之JavaCC
  19. css布局------块元素水平垂直居中的四种方法
  20. Ubuntu系统上All-in-one部署OpenStack

热门文章

  1. python 虚拟环境的安装
  2. 15 ~ express ~ 用户数据分页原理和实现
  3. PHP常用的数学函数和字符串函数
  4. Pycharm2020最新激活码|永久激活(附最新激活码和插件)
  5. c# 属性 (get、set)
  6. 吴裕雄--天生自然C++语言学习笔记:C++ 存储类
  7. 修改完Apache的配置文件,重启Apache后,仍无法打开网页
  8. Multiarmed Bandit Algorithm在股票中的应用
  9. Java 14 都要来了,为什么还有这么多人固守Java8?
  10. 深入浅出Python装饰器