POJ2778&HDU2243&POJ1625(AC自动机+矩阵/DP)
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)的更多相关文章
- hdu2243之AC自动机+矩阵乘法
考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- [poj2778]DNA Sequence(AC自动机+矩阵快速幂)
题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列.(仅含A,T,C,G四个字符) 解题关键:AC自动机,实际上就是一个状态转移图,注意能少取模就少取模, ...
- POJ2778 DNA Sequence(AC自动机 矩阵)
先使用AC自动机求得状态转移关系,再建立矩阵,mat[i][j]表示一步可从i到j且i,j节点均非终止字符的方案数,则此矩阵的n次方表示n步从i,到j的方法数. #include<cstdio& ...
- BZOJ 1009 GT考试(ac自动机+矩阵DP)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1009 题意:给定一个长度为m的串s.有多少种长度为n的串不包含s? 思路:(1)将s插入 ...
- 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 ...
- 关于AC自动机和DP的联系
首先是描述个大概.不说一些特殊的DP 或者借用矩阵来状态转移 (这些本质都是一样的). 只讲AC自动机和DP的关系(个人理解). AC自动机 又可以叫做状态机. 我一开始的认为.AC 自动机提供了一些 ...
- bzoj 2553: [BeiJing2011]禁忌 AC自动机+矩阵乘法
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2553 题解: 利用AC自动机的dp求出所有的转移 然后将所有的转移储存到矩阵中,进行矩阵 ...
- Censored! POJ - 1625 AC自动机+大数DP
题意: 给出一n种字符的字典,有p个禁用的单词, 问能组成多少个不同的长度为m的合法字符串.(m<=50) 题解: 是不是个我们之前做的题目非常非常像,题意都一样. 直接将上次写的AC自动机+矩 ...
- 【HDU3530】 [Sdoi2014]数数 (AC自动机+数位DP)
3530: [Sdoi2014]数数 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 682 Solved: 364 Description 我们称一 ...
随机推荐
- 用CodeViz绘制函数调用关系图(call graph)
CodeViz是<Understanding The Linux Virtual Memory Manager>(at Amazon,下载地址在页尾)的作者 Mel Gorman 写的一款 ...
- Binding to the Most Recent Visual Studio Libraries--说的很详细,很清楚
Every version of Visual Studio comes with certain versions of the Microsoft libraries, such as the C ...
- jmeter summariser(命令行执行时的输出) 、查看结果树等结果中文乱码
在使用jmeter测试时,如果你的sampler名字为中文.或者输出的结果信息有中文,你会发现它们都是乱码,非常蛋碎!原因是: jmeter的默认编码为:ISO-8859-1, 解决方案就是要修改它 ...
- linux 新建用户、用户组 以及为新用户分配权限
Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号 一方面可以帮助系统管理员对使用系统的用户进 ...
- poj2750Potted Flower (线段树)
http://poj.org/problem?id=2750 之前做过类似的题 把一段的左连续最大.最小 右连续最大及最小及中间的连续更新出 就可以算出这段最大的连续和 注意不能全部加上 加上一特判 ...
- freemarker跳出循环
break语句跳出当前循环,如下: <#list table.columns as c> <#if c.isPK> &l ...
- 陈正冲老师对于c语言野指针的解释
那到底什么是野指针呢?怎么去理解这个“野”呢?我们先看别的两个关于“野”的词: 野孩子:没人要,没人管的孩子:行为动作不守规矩,调皮捣蛋的孩子.野狗:没有主人的狗,没有链子锁着的狗,喜欢四处咬人. 对 ...
- sockaddr和sockaddr_in的区别(转载)
原文链接:http://kenby.iteye.com/blog/1149001 struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址. 在各种系统调 ...
- Weblogic11g安装
我们在64位的服务器上为提高性能要安装64位的weblogic.经常在网上看到有人问,weblogic有64位的么?weblogic需要破解么? weblogic有专门的64位版本,这里安装的是web ...
- Android MVP架构分析
App架构在Android开发者中一直是讨论比较多的一个话题,目前讨论较多的有MVP.MVVM.Clean这三种.google官方对于架构的态度一直是非常开放的,让开发者自主选择组织和架构app的方式 ...