poj2778
题意:给出字符串长度n(<=2000000000),给出不可以包含的序列,最多10个,每个长度最大是10。问长度为n的合法序列有多少个?序列中只可能包含ACTG四个字符。
分析:AC自动机(DFA)+矩阵快速幂
ac自动机上的等价态:
等价态即用fail指针连接的点,在行走fail指针时匹配的字符数量并没有发生变化,因此这些点可以看成是相同的匹配状态。
通常有两种方法处理等价态,第一是互为等价态的点各自记录各自的信息。匹配的时候需要遍历所有等价态以判断是否匹配成功。next指针可能为空,需要匹配时进行判断是否需要走fail指针。
第二是所有等价态中的点记录本身以及所有比它浅的点的信息总和(匹配成功的单词总数),匹配时不需要走等价态以判断匹配成功与否。next指针不为空,直接指向本应通过fail指针寻找到的那个状态。
ac自动机与矩阵:
在ac自动机上,每一个从根出发并在自动机上行走的任意长度的路径都代表了一个字符串。
把ac自动机看成一个有向图的话我们可以提取它的邻接矩阵(可达矩阵),matrix[i][j]表示i和j是否相邻。
这个矩阵的n次幂matrix^n[i][j]表示从i恰好走n步到达j的路径有几条。
那可达矩阵对等价态是怎么处理的呢?如果考虑等价态,一个状态的可到达状态实在是太多了。因此我们这里认为的可达只是用地二中方法处理等价态时,next指针直接指向的被认为可达。
本题其实就是在ac自动机上找出 从根出发的 长度为n的 不经过任何匹配成功态的 路径数量。
这个只需要用矩阵快速幂来计算即可,一个状态是否是匹配成功态的。注意判断成功态和等价态的问题。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std; #define D(x) #define MAX_LEN 20
#define MAX_CHILD_NUM 4
#define MAX_NODE_NUM 100005 int st_num, len;
int matrix_size;
int node_cnt; struct node
{
node *fail;
node *next[MAX_CHILD_NUM];
int count; //how many words are matched when reach this node
}trie[MAX_NODE_NUM], *root = trie; void ac_init()
{
memset(trie, , sizeof(trie));
node_cnt = ;
} int get_id(char ch)
{
if (ch == 'A')
return ;
if (ch == 'C')
return ;
if (ch == 'T')
return ;
return ;
} void insert(node *root, char *str)
{
node *p = root;
int index;
for (int i = ; str[i]; i++)
{
index = get_id(str[i]);
if (p->next[index] == NULL)
{
p->next[index] = trie + node_cnt;
node_cnt++;
}
p = p->next[index];
}
p->count++;
} void build_ac_automation(node *root)
{
queue<node*> q;
int i;
root->fail = NULL;
q.push(root);
while (!q.empty())
{
node *temp = q.front();
q.pop();
node *p = NULL;
for (i = ; i < MAX_CHILD_NUM; i++)
{
p = temp->fail;
while (p != NULL && p->next[i] == NULL)
p = p->fail;
if (temp->next[i] != NULL)
{
if (p == NULL)
temp->next[i]->fail = root;
else
{
temp->next[i]->fail = p->next[i];
temp->next[i]->count += p->next[i]->count;
}
q.push(temp->next[i]);
}else
{
if (p == NULL)
temp->next[i] = root;
else
temp->next[i] = p->next[i];
}
}
}
} int query(node *root, char* str)
{
int cnt = , index;
node *p = root;
for (int i = ; str[i]; i++)
{
index = get_id(str[i]);
p = p->next[index];
p = (p == NULL) ? root : p;
node *temp = p;
cnt += temp->count;
//marks count as -1 to prevent from matching again
while (temp != root && temp->count != -)
{
temp->count = -;
temp = temp->fail;
}
}
return cnt;
} void input()
{
scanf("%d%d", &st_num, &len);
for (int i = ; i < st_num; i++)
{
char st[MAX_LEN];
scanf("%s", st);
insert(root, st);
}
} #define MAX_MATRIX_SIZE 101
#define MOD 100000 struct Matrix
{
int order;
int num[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE]; Matrix()
{} Matrix(int ord)
{
order = ord;
} void init()
{
for (int i = ; i < order; i++)
{
for (int j = ; j < order; j++)
{
num[i][j] = ;
}
}
}
void output()
{
for (int i = ; i < order; i++)
{
for (int j = ; j < order; j++)
{
printf("%d ", num[i][j]);
}
puts("");
}
}
}; Matrix operator*(Matrix ma, Matrix mb)
{
int ord = ma.order;
Matrix numc(ord);
numc.init();
int i, j, k;
for (i = ; i < ord; i++)
{
for (k = ; k < ord; k++)
{
if (ma.num[i][k] == )
continue;
for (j = ; j < ord; j++)
{
long long temp = ma.num[i][k] * (long long)mb.num[k][j];
temp %= MOD;
numc.num[i][j] += temp;
numc.num[i][j] %= MOD;
D(printf("%d %d %d\n", i, j, numc.num[i][j]);)
}
}
}
return numc;
} Matrix matrix_power(Matrix ma, int x)
{
int ord = ma.order;
Matrix numc(ord);
numc.init();
for (int i = ; i < ord; i++)
{
numc.num[i][i] = ;
}
for (; x; x >>= )
{
if (x & )
{
numc = numc * ma;
}
ma = ma * ma;
}
return numc;
} void extract_matrix(Matrix &matrix)
{
matrix.order = node_cnt;
matrix.init();
for (int i = ; i < node_cnt; i++)
{
for (int j = ; j < MAX_CHILD_NUM; j++)
{
if (trie[i].next[j] == NULL)
continue;
int temp = trie[i].next[j] - trie;
if (trie[temp].count == )
{
matrix.num[i][temp] += ;
//D(printf("%d %d\n", i, temp);)
}
}
}
} int main()
{
ac_init();
input();
build_ac_automation(root);
Matrix matrix;
extract_matrix(matrix);
D(matrix.output();)
Matrix power = matrix_power(matrix, len);
int ans = ;
for (int i = ; i < node_cnt; i++)
ans = (ans + power.num[][i]) % MOD;
D(power.output();)
printf("%d\n", ans);
return ;
}
poj2778的更多相关文章
- 【POJ2778】DNA Sequence(AC自动机,DP)
题意: 生物课上我们学到,DNA序列中只有A, C, T和G四种片段. 经科学发现,DNA序列中,包含某些片段会产生不好的基因,如片段"ATC"是不好片段,则"AGATC ...
- POJ2778&HDU2243&POJ1625(AC自动机+矩阵/DP)
POJ2778 题意:只有四种字符的字符串(A, C, T and G),有M中字符串不能出现,为长度为n的字符串可以有多少种. 题解:在字符串上有L中状态,所以就有L*A(字符个数)中状态转移.这里 ...
- 【POJ2778】AC自动机+矩阵乘法
DNA Sequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14758 Accepted: 5716 Descrip ...
- poj2778(AC 自动机)
poj2778 题意 构造只包含 \(A, T, C, G\) 的字符串,且满足不出现指定的一些字符串,问长度为 \(n\) 的字符串有多少种 ? 分析 AC 自动机 + 矩阵快速幂的神题 ,知识点很 ...
- 【AC自动机】【矩阵乘法】poj2778 DNA Sequence
http://blog.csdn.net/morgan_xww/article/details/7834801 讲得很好~可以理解自动机的本质,就是一个用来状态转移的东西~对于确定的输入而言,可以从初 ...
- POJ2778 DNA sequence
题目大意:给出m个疾病基因片段(m<=10),每个片段不超过10个字符.求长度为n的不包含任何一个疾病基因片段的DNA序列共有多少种?(n<=2000000000) 分析:本题需要对m个疾 ...
- POJ2778 DNA Sequence(AC自动机 矩阵)
先使用AC自动机求得状态转移关系,再建立矩阵,mat[i][j]表示一步可从i到j且i,j节点均非终止字符的方案数,则此矩阵的n次方表示n步从i,到j的方法数. #include<cstdio& ...
- POJ2778 DNA Sequence(AC自动机+矩阵快速幂)
题目给m个病毒串,问不包含病毒串的长度n的DNA片段有几个. 感觉这题好神,看了好久的题解. 所有病毒串构造一个AC自动机,这个AC自动机可以看作一张有向图,图上的每个顶点就是Trie树上的结点,每个 ...
- poj2778(AC自动机+矩阵快速幂)
题意:给你n个字符串,问你长度为m的字符串且字符串中不含有那n个子串的字符串的数量 解题思路:这道题一开始就不太懂,还以为是组合数学的题目,后面看了别人的博客,才知道这是属于AC自动机的另一种用法,是 ...
随机推荐
- poj3580 伸展树(区间翻转 区间搬移 删除结点 加入结点 成段更新)
好题.我做了很久,学了大牛们的区间搬移.主要的代码都有注释. #include<cstdio> #include<cstring> #include<iostream&g ...
- 基于Bootstrap的jQuery开关按钮插件
按钮 下载 使用方法 首先要在页面中引入依赖文件: jquery.Bootstrap.Bootstrap Switch CSS和Bootstrap Switch JS.这里用的是bootstr ...
- 【POJ 2886】Who Gets the Most Candies?
题意 约瑟夫问题的升级版,每次出去的是前一个出去的人位置+手上的数字(正往前,负往后).第i个出去的人拿的糖是i的约数的个数.求拿糖最多的人和他的糖果数. 分析 线段树单点更新,反素数. 我竟然WA在 ...
- Threat Risk Modeling Learning
相关学习资料 http://msdn.microsoft.com/en-us/library/aa302419(d=printer).aspx http://msdn.microsoft.com/li ...
- HDU 2896
传送门:HDU 2896 病毒侵袭 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- spring bean实例化方式
注意:xml配置中bean节点下scope属性默认值为singleton(单例),在需要多例的情况下需要配置成prototype spring提供三种实例化方式:默认构造.静态工厂.实例工厂 一.默认 ...
- Windows下绘制数学函数图像的方法
一.安装相关软件 在Windows中安装VirtualBox: 在VirtualBox中安装Ubuntu Server: 在Ubuntu Server中安装cifs-utils:sudo apt-ge ...
- Hbase Shell常用命令
hbase shell常用的操作命令有create,describe,disable,drop,list,scan,put,get,delete,deleteall,count,status等,通过h ...
- 菲涅尔反射(Fresnel Reflection)
离线渲染中,通常可以用kd,ks,kt(分别代表物体的漫反射系数,镜面反射系数,透射系数)来简单地描述一个物体的基本材质,例如,我们将一个物体设置为:kd=0,ks=0.1,kt=0.9,即代表一束光 ...
- TCPCopy 应用
TCPCopy 使用方法 TCPCopy是一种请求复制(所有基于tcp的packets)工具,可以把在线请求导入到测试系统中去.目前此工具已经广泛应用于国内各大互联网公司. TCPCopy七大功能1) ...