POJ2778

题意:只有四种字符的字符串(A, C, T and G),有M中字符串不能出现,为长度为n的字符串可以有多少种。

题解:在字符串上有L中状态,所以就有L*A(字符个数)中状态转移。这里自动机的build的hdu2222略有不同。

那一题中通过询问时循环来求she的he,但是如果he不能出现,she就算不是禁止的字符串也不可出现,所以在build的时候就记录所有不能出现的状态。

if (end[ fail[now] ]) end[now]++;

然后用一个矩阵F来记录可以相互到达的状态就OK了。

矩阵可以理解为用长度为1的字符串两个状态可以相互达到,而F=F^n,F[i][j]就是字符串长度为n时状态i到状态j的路径。

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
#include <set>
using namespace std; const int N = ;
const int A = ;
const int M = ;
const int MOD = ; typedef vector<int> vec;
typedef vector<vec> mat; mat mul(mat &A, mat &B)
{
mat C(A.size(), vec(B[].size()));
for (int i = ; i < A.size(); ++i) {
for (int k = ; k < B.size(); ++k) {
for (int j = ; j < B[].size(); ++j) {
C[i][j] = (C[i][j] + (long long)A[i][k] * B[k][j]) % MOD;
}
}
}
return C;
} // A^n
mat pow(mat A, int n)
{
mat B(A.size(), vec(A.size()));
for (int i = ; i < A.size(); ++i)
B[i][i] = ;
while (n > ) {
if (n & ) B = mul(B, A);
A = mul(A, A);
n >>= ;
}
return B;
} struct ACAutomata { int next[N][A], fail[N], end[N];
int root, L; int idx(char ch)
{
switch(ch) {
case 'A': return ;
case 'C': return ;
case 'T': return ;
case 'G': return ;
}
return -;
}
int newNode()
{
for (int i = ; i < A; ++i) next[L][i] = -;
end[L] = ;
return L++;
}
void init()
{
L = ;
root = newNode();
}
void insert(char buf[])
{
int len = strlen(buf);
int now = root;
for (int i = ; i < len; ++i) {
int ch = idx(buf[i]);
if (next[now][ch] == -) next[now][ch] = newNode();
now = next[now][ch];
}
end[now]++;
}
void build()
{
queue<int> Q;
fail[root] = root;
for (int i = ; i < A; ++i) {
if (next[root][i] == -) {
next[root][i] = root;
} else {
fail[ next[root][i] ] = root;
Q.push( next[root][i] );
}
}
while (Q.size()) {
int now = Q.front();
Q.pop();
if (end[ fail[now] ]) end[now]++; //!!
for (int i = ; i < A; ++i) {
if (next[now][i] == -) {
next[now][i] = next[ fail[now] ][i];
} else {
fail[ next[now][i] ] = next[ fail[now] ][i];
Q.push(next[now][i]);
}
}
}
} int query(int n)
{
mat F(L, vec(L));
for (int i = ; i < L; ++i) {
for (int j = ; j < L; ++j) {
F[i][j] = ;
}
}
for (int i = ; i < L; ++i) {
for (int j = ; j < A; ++j) {
int nt = next[i][j];
if (!end[nt]) F[i][nt]++;
}
}
F = pow(F, n);
int res = ;
for (int i = ; i < L; ++i) {
res = (res + F[][i]) % MOD;
}
return res;
} } ac; char buf[];
int main()
{
int m, n;
while (~scanf("%d%d", &m, &n)) {
ac.init();
while (m--) {
scanf("%s", buf);
ac.insert(buf);
}
ac.build();
printf("%d\n", ac.query(n));
} return ;
}

HDU 2243上题要求不存在给定字符串,而这题要求存在至少一个。于是方法就是总方法减去不存在的就是答案了。

题目要求是小于等于L的,所以矩阵加一维记录前缀和就好了。

#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ull;
typedef vector<ull> vec;
typedef vector<vec> mat;
const int N = ;
const int A = ;
const int M = ; mat mul(mat &A, mat &B)
{
mat C(A.size(), vec(B[].size()));
for (int i = ; i < A.size(); ++i) {
for (int k = ; k < B.size(); ++k) {
for (int j = ; j < B[].size(); ++j) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
} mat pow(mat A, ull n)
{
mat B(A.size(), vec(A.size()));
for (int i = ; i < A.size(); ++i)
B[i][i] = ;
while (n > ) {
if (n & ) B = mul(B, A);
A = mul(A, A);
n >>= ;
}
return B;
} struct ACAutomata { int next[N][A], fail[N], end[N];
int root, L; int idx(char ch)
{
return ch - 'a';
}
int newNode()
{
for (int i = ; i < A; ++i) next[L][i] = -;
end[L] = ;
return L++;
}
void init()
{
L = ;
root = newNode();
}
void insert(char buf[])
{
int len = strlen(buf);
int now = root;
for (int i = ; i < len; ++i) {
int ch = idx(buf[i]);
if (next[now][ch] == -) next[now][ch] = newNode();
now = next[now][ch];
}
end[now]++;
}
void build()
{
queue<int> Q;
fail[root] = root;
for (int i = ; i < A; ++i) {
if (next[root][i] == -) {
next[root][i] = root;
} else {
fail[ next[root][i] ] = root;
Q.push( next[root][i] );
}
}
while (Q.size()) {
int now = Q.front();
Q.pop();
if (end[ fail[now] ]) end[now]++;
for (int i = ; i < A; ++i) {
if (next[now][i] == -) {
next[now][i] = next[ fail[now] ][i];
} else {
fail[ next[now][i] ] = next[ fail[now] ][i];
Q.push(next[now][i]);
}
}
}
} ull query(ull n)
{
mat F(L+, vec(L+));
for (int i = ; i <= L; ++i) {
for (int j = ; j <= L; ++j) {
F[i][j] = ;
}
}
for (int i = ; i <= L; ++i) F[i][L] = ;
for (int i = ; i < L; ++i) {
for (int j = ; j < A; ++j) {
int nt = next[i][j];
if (!end[nt]) F[i][nt]++;
}
}
F = pow(F, n+);
return F[][L] - ;
} } ac; char aff[];
int main()
{
int n;
ull m;
while (~scanf("%d%llu", &n, &m)) {
ac.init();
while (n--) {
scanf("%s", aff);
ac.insert(aff);
}
ac.build();
ull ans1 = ac.query(m);
mat F(, vec());
mat S(, vec()); S[][] = ; S[][] = ;
F[][] = ; F[][] = ;
F[][] = ; F[][] = ;
F = pow(F, m);
S = mul(F, S);
ull ans2 = S[][];
printf("%llu\n", ans2 - ans1);
}
return ;
}

POJ1625

同poj2778,不过没有取模操作,需要大数。

大数不可以矩阵快速幂吗?内存不够……

使用dp递推,递推公式也比较简单。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <map> using namespace std; typedef vector<int> vec;
typedef vector<vec> mat;
const int N = ;
const int A = ; map<char, int> mp; struct BigInt
{
const static int mod = ;
const static int DLEN = ;
int a[],len;
BigInt()
{
memset(a,,sizeof(a));
len = ;
}
BigInt(int v)
{
memset(a,,sizeof(a));
len = ;
do
{
a[len++] = v%mod;
v /= mod;
}while(v);
}
BigInt(const char s[])
{
memset(a,,sizeof(a));
int L = strlen(s);
len = L/DLEN;
if(L%DLEN)len++;
int index = ;
for(int i = L-;i >= ;i -= DLEN)
{
int t = ;
int k = i - DLEN + ;
if(k < )k = ;
for(int j = k;j <= i;j++)
t = t* + s[j] - '';
a[index++] = t;
}
}
BigInt operator +(const BigInt &b)const
{
BigInt res;
res.len = max(len,b.len);
for(int i = ;i <= res.len;i++)
res.a[i] = ;
for(int i = ;i < res.len;i++)
{
res.a[i] += ((i < len)?a[i]:)+((i < b.len)?b.a[i]:);
res.a[i+] += res.a[i]/mod;
res.a[i] %= mod;
}
if(res.a[res.len] > )res.len++;
return res;
}
BigInt operator *(const BigInt &b)const
{
BigInt res;
for(int i = ; i < len;i++)
{
int up = ;
for(int j = ;j < b.len;j++)
{
int temp = a[i]*b.a[j] + res.a[i+j] + up;
res.a[i+j] = temp%mod;
up = temp/mod;
}
if(up != )
res.a[i + b.len] = up;
}
res.len = len + b.len;
while(res.a[res.len - ] == &&res.len > )res.len--;
return res;
}
void output()
{
printf("%d",a[len-]);
for(int i = len-;i >= ;i--)
printf("%04d",a[i]);
printf("\n");
}
}; struct ACAutomata { int next[N][A], fail[N], end[N];
int root, L; int idx(char ch)
{
return mp[ch];
}
int newNode()
{
for (int i = ; i < A; ++i) next[L][i] = -;
end[L] = ;
return L++;
}
void init()
{
L = ;
root = newNode();
}
void insert(char buf[])
{
int len = strlen(buf);
int now = root;
for (int i = ; i < len; ++i) {
int ch = idx(buf[i]);
if (next[now][ch] == -) next[now][ch] = newNode();
now = next[now][ch];
}
end[now]++;
}
void build()
{
queue<int> Q;
fail[root] = root;
for (int i = ; i < A; ++i) {
if (next[root][i] == -) {
next[root][i] = root;
} else {
fail[ next[root][i] ] = root;
Q.push( next[root][i] );
}
}
while (Q.size()) {
int now = Q.front();
Q.pop();
if (end[ fail[now] ]) end[now]++; //!!
for (int i = ; i < A; ++i) {
if (next[now][i] == -) {
next[now][i] = next[ fail[now] ][i];
} else {
fail[ next[now][i] ] = next[ fail[now] ][i];
Q.push(next[now][i]);
}
}
}
}
mat query(int n)
{
mat F(L, vec(L));
for (int i = ; i < L; ++i) {
for (unsigned j = ; j < mp.size(); ++j) {
int nt = next[i][j];
if (!end[nt]) F[i][nt]++;
}
}
return F;
} } ac; char word[];
BigInt dp[][];
int main()
{
int n, m, p;
while (~scanf("%d%d%d", &n, &m, &p)) {
ac.init();
getchar();
gets(word);
mp.clear();
for (unsigned i = ; i < strlen(word); ++i) mp[ word[i] ] = i;
while (p--) {
gets(word);
ac.insert(word);
}
ac.build();
mat F = ac.query(m); int now = ;
dp[now][] = ;
for (int i = ; i < ac.L; ++i) dp[now][i] = ;
for (int i = ; i <= m; ++i) {
now ^= ;
for (int j = ; j < ac.L; ++j) dp[now][j] = ;
for (int j = ; j < ac.L; ++j)
for (int k = ; k < ac.L; ++k)
if (F[j][k]) dp[now][k] = dp[now][k] + dp[now^][j] * F[j][k];
}
BigInt res = ;
for (int i = ; i < ac.L; ++i) res = res + dp[now][i];
res.output();
}
return ;
}

POJ2778&HDU2243&POJ1625(AC自动机+矩阵/DP)的更多相关文章

  1. hdu2243之AC自动机+矩阵乘法

    考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  2. [poj2778]DNA Sequence(AC自动机+矩阵快速幂)

    题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列.(仅含A,T,C,G四个字符) 解题关键:AC自动机,实际上就是一个状态转移图,注意能少取模就少取模, ...

  3. POJ2778 DNA Sequence(AC自动机 矩阵)

    先使用AC自动机求得状态转移关系,再建立矩阵,mat[i][j]表示一步可从i到j且i,j节点均非终止字符的方案数,则此矩阵的n次方表示n步从i,到j的方法数. #include<cstdio& ...

  4. BZOJ 1009 GT考试(ac自动机+矩阵DP)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1009 题意:给定一个长度为m的串s.有多少种长度为n的串不包含s? 思路:(1)将s插入 ...

  5. poj2778 DNA Sequence(AC自动机+矩阵快速幂)

    Description It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's ve ...

  6. 关于AC自动机和DP的联系

    首先是描述个大概.不说一些特殊的DP 或者借用矩阵来状态转移 (这些本质都是一样的). 只讲AC自动机和DP的关系(个人理解). AC自动机 又可以叫做状态机. 我一开始的认为.AC 自动机提供了一些 ...

  7. bzoj 2553: [BeiJing2011]禁忌 AC自动机+矩阵乘法

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2553 题解: 利用AC自动机的dp求出所有的转移 然后将所有的转移储存到矩阵中,进行矩阵 ...

  8. Censored! POJ - 1625 AC自动机+大数DP

    题意: 给出一n种字符的字典,有p个禁用的单词, 问能组成多少个不同的长度为m的合法字符串.(m<=50) 题解: 是不是个我们之前做的题目非常非常像,题意都一样. 直接将上次写的AC自动机+矩 ...

  9. 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)

    3530: [Sdoi2014]数数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 682  Solved: 364 Description 我们称一 ...

随机推荐

  1. pthread_create用法

    linux下用C开发多线程程序,Linux系统下的多线程遵循POSIX线程接口,称为pthread. #include <pthread.h> int pthread_create(pth ...

  2. C++11 FAQ中文版--转

    更新至英文版October 3, 2012 译者前言: 经过C++标准委员会的不懈努力,最新的ISO C++标准C++11,也即是原来的C++0x,已经正式发布了.让我们欢迎C++11! 今天获得St ...

  3. a标签的link、visited、hover、active的顺序

    a标签的link.visited.hover.active是有一定顺序的,以下是我一直在用的一个顺序,能正确显示四个颜色,我也不知道有没有其他的顺序能正确显示,如果你没办法判断哪个是对的,那就先用这个 ...

  4. 多线程(一)NSThread

    iOS中多线程的实现方案: 技术 语言 线程生命周期 使用频率 pthread C 程序员自行管理 几乎不用 NSthread OC 程序员自行管理 偶尔使用 GCD C 自动管理 经常使用 NSOp ...

  5. cocos2d-x 扩充引擎基类功能 引起的头文件重复包含问题的分析

    c++ 头文件包含 原因的分析:   c++  头文件的循环引用是指: .h 里面的里面的头文件的相互包含的,引起的重复引用的问题.cpp 里面包含头文件是不存在重复引用的问题(因为CPP没有#ifn ...

  6. Web开发的绝美网站

    http://paranimage.com/ http://sixrevisions.com/graphics-design/

  7. Centos之LAMP环境搭建

    原文:http://blog.sina.com.cn/s/blog_c02ed6590101d2sl.html 一.安装 MySQL 首先来进行 MySQL 的安装.打开超级终端,输入: [root@ ...

  8. Android:自定义适配器

    无论是ArrayAdapter还是SimpleAdapter都继承了BaseAdapter,自定义适配器同样继承BaseAdapter 实例:Gallery实现图片浏览器 <?xml versi ...

  9. Java API ——String类

    1.String类概述 · 字符串是由多个字符组成的一串数据(字符序列),也可以看成是一个字符数组. · 字符串字符值“abc”也可以看成是一个字符串对象. · 字符串是常量,一旦被赋值,就不能被改变 ...

  10. socket.io 使用

    socket.io是一个以实现跨浏览器.跨平台的实时应用为目的的项目.针对不同的浏览器版本或者不同客户端会做自动降级处理,选择合适的实现方式(websocket, long pull..),隐藏实现只 ...