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 我们称一 ...
随机推荐
- C++11新特性:Lambda函数(匿名函数)
声明:本文参考了Alex Allain的文章http://www.cprogramming.com/c++11/c++11-lambda-closures.html 加入了自己的理解,不是简单的翻译 ...
- HDU1180+BFS
bfs思路:三维标记状态 && 处理好 - | 和时刻的关系即可 /* bfs 思路:三维标记状态 && 处理好 - | 和时刻的关系即可 */ #include< ...
- linux为命令取别名
在linux的命令中,有些命令很长并且经常使用到,我们可以为命令添加一个别名,格式如下: $ alias 别名='命令' 例如: # 列出home文件夹的文件 $ alias lsh='ls -l / ...
- Android中如何取消调转界面后EditText默认获取聚焦问题
最近在做一个项目,当我点击跳转至一个带有EditText的界面后,模拟器中的软键盘会自动弹出,严重影响了用户体验.在网上找了资料,现总结如下. 我们知道,EditText有一个 android:foc ...
- SQLite入门与分析(三)---内核概述(1)
写在前面:从本章开始,我们开始进入SQLite的内核.为了能更好的理解SQLite,我先从总的结构上讨论一下内核,从全局把握SQLite很重要.SQLite的内核实现不是很难,但是也不是很简单.总的来 ...
- 安装Ubuntu双系统系列——更换源
Ubuntu 有一个非常有用的命令 apt-get,它可以帮助你下载软件,还可以安装,下载并安装的命令是 apt-get install. 那Ubuntu默认是从哪里下载软件呢,这可以查看文件/etc ...
- Why it is good practice to declare loggers private, static, and final?
// Jakarta Commons Loggingprivate static final Log log = LogFactory.getLog(MyClass.class);The above ...
- linux文件系统-基本磁盘2
直入主题-基本磁盘 硬盘数据按照不同特点和作用大致分为5部分:MBR区.DBR区.FAT区.DIR区和DATA区 1.MBR MBR(Main Boot Record 主引导记录区)位于整个硬盘的0磁 ...
- int21 h
表:DOS系统功能调INT 21H AH 功能 调用参数 返回参数 00 程序终止(同INT 20H) CS=程序段前缀 01 键盘输入并回显 AL=输入字符 02 显示输出 DL=输出字符 03 异 ...
- xp宿主机和VMware下Ubuntu12.04共享文件夹
VMware下Windows与Linux共享文件的方法有很多,比如Samba等等,我这里介绍简单地通过设置VMware来达到共享的目的. 打开VMware的设置,在"options" ...