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. 关于C的一些理解

    关于字符数组和字符指针 关于相互赋值问题一只有疑问,其实是自己搞不清指针和地址的关系.地址可以指向一块内存但是不一定存在于内存,比如字符数组名,数组名是地址,但是不实际存在于内存中,无法修改,而字符指 ...

  2. 新建一个struts2项目

    1,新建-动态web项目: 2,将struts2的必要jar包复制到WEB-INF\lib文件夹下,一共有9个,如图一所示. 图一 3,配置web.xml文件,将以下内容写到web.xml文件中. & ...

  3. DSPLIB for C6455+CCSv3.3

    问题描述: Hello everybody, I was looking for DSPLIB libraries optimized for C6455 processors. I found th ...

  4. CenOS7.1安装VNC——让win7远程桌面linux

    参考:http://wic.xingning.gov.cn/blog/29 https://linux.cn/article-5335-1.html 1.检查是否安装VNC, rpm -q tiger ...

  5. 2.2linux内核移植简介

    1,编译linux3.5出错 root@phone-desktop:/opt/FriendlyARM/tiny4412/Linux/linux-3.5# makescripts/kconfig/con ...

  6. C#中配置文件的使用

    1. 向项目添加app.config文件: 右击项目名称,选择“添加”→“添加新建项”,在出现的“添加新项”对话框中,选择“添加应用程序配置文件”:如果项目以前没有配置文件,则默认的文件名称为“app ...

  7. storm - 基础概念整理

    理论 Hadoop的出现虽然为大数据计算提供了一条捷径,但其仍然存在自身难以克服的缺点:实时性不足.Hadoop的一轮计算的启动需要较长时间,因此其满足不了对实时性有较高要求的场景. Storm由此应 ...

  8. Java和.NET在开发中的不同盘点

    我是用VS2008和VS2010开发.NET程序,通过MyEclipse8.5开发JAVA程序,下面从IDE.语言.插件的不同点来做下简单的说明.但由于经验知识还有限,本篇文章只能从比较表面的以及自己 ...

  9. NOI2002robot

    这题又是纯数论题…… 独立数就是欧拉函数,政客和军人的含义已经说的很清楚了,学者是最多的…… 首先,如果我们知道了政客和军人的答案,那就只要用n的所有因子的欧拉函数值减去这两个值,然后取模就行了. 但 ...

  10. 使用BusyBox制作嵌入式Linux根文件系统

    STEP 1:构建目录结构  创建根文件系统目录,主要包括以下目录/dev  /etc /lib  /usr  /var /proc /tmp /home /root /mnt /bin  /sbin ...