POJ 2778 (AC自动机 矩阵快速幂)
2016-06-16 16:46
288 查看
题目链接:点击这里
题意:求不出现任意一个模式串的长度为m的文本串的数量.
建立AC自动机,文本串生成的过程可以看成是在自动机上某一个节点往4个方向上走一步,因为不能出现模式串,所以不能走到模式串结尾的节点.所以可以建立矩阵,a[i][j]表示从节点i到节点j的方案数. 根据邻接矩阵的定义, 这个矩阵的m次就是从某一个点走m步到达另一个点的方案数, 统计下就好了.
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <queue> using namespace std; #define maxn 111 #define mod 100000 int n; long long m; char str[11][11]; int tot; void change (char *s) { int len = strlen (s); for (int i = 0; i < len; i++) { if (s[i] == 'A') s[i] = 'a'; else if (s[i] == 'C') s[i] = 'b'; else if (s[i] == 'T') s[i] = 'c'; else s[i] = 'd'; } return ; } struct M { long long a[maxn][maxn]; M () { memset (a, 0, sizeof a); } M operator * (const M &gg) const { M ans; memset (ans.a, 0, sizeof ans.a); for (int i = 0; i < tot; i++) { for (int j = 0; j < tot; j++) { for (int l = 0; l < tot; l++) { ans.a[i][j] += a[i][l]*gg.a[l][j]; ans.a[i][j] %= mod; } } } return ans; } void show () { for (int i = 0; i < tot; i++) { for (int j = 0; j < tot; j++) cout << a[i][j] << " "; cout << endl; } } }; M qpow (M a, long long k) { M ans; int i, j; for (i = 0; i < tot; ++i) for (j = 0; j < tot; ++j) ans.a[i][j] = (i == j ? 1 : 0); for(; k; k >>= 1) { if (k&1) ans = ans*a; a = a*a; } return ans; } struct trie { int next[maxn][4], fail[maxn], end[maxn]; int root, cnt; int new_node () { memset (next[cnt], -1, sizeof next[cnt]); end[cnt++] = 0; return cnt-1; } void init () { cnt = 0; root = new_node (); } void insert (char *buf) {//字典树插入一个单词 int len = strlen (buf); int now = root; for (int i = 0; i < len; i++) { int id = buf[i]-'a'; if (next[now][id] == -1) { next[now][id] = new_node (); } now = next[now][id]; } end[now]++; } void build () {//构建fail指针 queue <int> q; fail[root] = root; for (int i = 0; i < 4; i++) { if (next[root][i] == -1) { next[root][i] = root; } else { fail[next[root][i]] = root; q.push (next[root][i]); } } while (!q.empty ()) { int now = q.front (); q.pop (); for (int i = 0; i < 4; i++) { if (next[now][i] == -1) { next[now][i] = next[fail[now]][i]; } else { fail[next[now][i]] = next[fail[now]][i]; q.push (next[now][i]); } } } } int f[maxn];//安全节点对应的节点编号 long long query () { M ans; memset (ans.a, 0, sizeof ans.a); memset (f, -1, sizeof f); tot = 0; for (int i = 0; i < cnt; i++) if (!end[i]) { bool flag = 1; int tmp = i; while (tmp != root) { if (end[tmp]) { flag = 0; break; } tmp = fail[tmp]; } if (flag) { f[i] = tot++; } } for (int i = 0; i < cnt; i++) if (f[i] != -1) {//构造矩阵 int u = f[i]; for (int id = 0; id < 4; id++) { int v = next[i][id]; if (f[v] != -1) { v = f[v]; ans.a[u][v]++; } } } //ans.show (); ans = qpow (ans, m); long long res = 0; for (int i = 0; i < tot; i++) { res += ans.a[0][i]; res %= mod; } return res; } }ac; int main () { while (scanf ("%d%lld", &n, &m) == 2) { ac.init (); for (int i = 1; i <= n; i++) { scanf ("%s", str[i]); change (str[i]); ac.insert (str[i]); } ac.build (); long long ans = ac.query (); printf ("%lld\n", ans); } return 0; }
相关文章推荐
- VB语言5“用户名”与“密码”实验报告
- 将树莓派作为自己的软件代码托管服务器!!!
- 使用MyBatis(12)动态SQL 完成分页查询
- oracle 游标变量REF Cursor
- 【C++】使用共享内存实现进程间通信
- POJ2104 整体二分、树套树
- Advanced JavaScript Array Methods: fill and reverse
- ByteBuffer的position、limit和capacity
- VB实验报告“找出二维数组n×m中的鞍点”
- matlab遍历指定路径下的文件夹
- APK Tool的问题:Exception in thread "main" brut.androlib.AndrolibException: Could not decode arsc file
- css3中的多列布局!也就是传说中的瀑布流布局
- background overdraw
- [Nutch]问题解决:Exception in thread "main" java.io.IOException: Job failed
- salesforce 零基础学习(三十一)关于LookUp字段点击Save时的Validation
- SSL 1338 最大匹配 人员分配
- Python安装及环境变量配置
- 只是为了存图片
- syslog-ng+loganalyzer(非常详细配置文件)部署收集操作日志
- 关于oop错误定位的学习