POJ 4052 AC自动机

【题意】:

给你n个字符串和一个文本,问有多少个字符串满足如下条件:该字符串包含在文本,该字符串不为其它字符串的子串。

【知识点】:

Ac自动机,处理字符串

【题解】:

集训比赛的时候当时被题目的数据量吓到了,不敢用ac自动机。但在网上看到题解时,然后瞬间就感觉自己想多了。。。

很水的一道ac自动机处理字符串的题目,先将查询的字符做成字典树,然后在文本中查找字符串是否存在。

在处理去子串上,我的做法是查找文本时去除后缀相同的包含子串。然后单独在搜索剩余可用字符串前缀相同子串。

【代码】:

  1 #include <map>
  2 #include <set>
  3 #include <cmath>
  4 #include <ctime>
  5 #include <queue>
  6 #include <stack>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstring>
 11 #include <sstream>
 12 #include <iostream>
 13 #include <algorithm>
 14 #include <bitset>
 15 #include <climits>
 16 using namespace std;
 17
 18 #define wh while
 19 #define inf (int)(~0u/2)
 20 #define FOR(i, n) for(int i = 0; i < n; i++)
 21 #define FOR1(i, n) for(int i = 1; i < n; i++)
 22 #define FOR2(i, n) for(int i = 0; i <= n; i++)
 23 #define REP(i,n) for(int i = 1; i <= n; i++)
 24 #define FORI(it,n) for(typeof(n.begin()) it = n.begin(); it != n.end(); it++)
 25 #define sf scanf
 26 #define pf printf
 27 #define frs first
 28 #define sec second
 29 #define psh push_back
 30 #define mkp make_pair
 31 #define PB(x) push_back(x)
 32 #define MP(x, y) make_pair(x, y)
 33 #define clr(abc,z) memset(abc,z,sizeof(abc))
 34 #define lt(v) v << 1
 35 #define rt(v) v << 1 | 1
 36 #define mid ((l + r) >> 1)
 37 #define lson l, mid, v << 1
 38 #define rson mid + 1, r, v << 1 | 1
 39
 40 #define fre freopen("1.txt", "r", stdin)
 41
 42 typedef long long LL;
 43 typedef long double LD;
 44
 45 const int maxn = 3000;
 46 const int maxlen = 1300;
 47 const int maxlen2 = 3e6 + 10;
 48 char st[maxn][maxlen];
 49 char ctmp[maxlen2 * 2];
 50 char text[maxlen2 * 2];
 51 bool vis[maxn];
 52
 53 const int SIGMA_SIZE = 26;
 54 const int MAXNODE = 3e6 + 10;
 55 const int MAXS = 150 + 10;
 56
 57 char* deal(char* res, char* s){
 58     int len = 0; int t = 0;
 59     for(int i = 0; s[i]; i++){
 60         if(s[i] == ‘[‘ || s[i] == ‘]‘) t = 0;
 61         else if(s[i] >= 0 && s[i] <= ‘9‘) t = t * 10 + s[i] - ‘0‘;
 62         else if(s[i] >= ‘A‘ && s[i] <= ‘Z‘){
 63             if(t == 0)
 64                 res[len++] = s[i];
 65             else{
 66                 while(t--)
 67                     res[len++] = s[i];
 68             }
 69         }
 70     }
 71     res[len] = ‘\0‘;
 72     return res;
 73 }
 74 struct AhoCorasickAutomata {
 75     int ch[MAXNODE][SIGMA_SIZE];
 76     int f[MAXNODE];
 77     int val[MAXNODE];
 78     int last[MAXNODE];
 79     int sz;
 80     void init() {
 81         sz = 1;
 82         memset(ch[0], 0, sizeof(ch[0]));
 83     }
 84     int idx(char c) {
 85         return c - ‘A‘;
 86     }
 87     void _insert(char *s, int v) {
 88         int u = 0, n = strlen(s);
 89         for(int i = 0; i < n; i++) {
 90             int c = idx(s[i]);
 91             if(!ch[u][c]) {
 92                 memset(ch[sz], 0, sizeof(ch[sz]));
 93                 val[sz] = 0;
 94                 ch[u][c] = sz++;
 95             }
 96             u = ch[u][c];
 97         }
 98         val[u] = v;
 99     }
100     void doA(int j) {
101         if(j) {
102             vis[val[j]] = true;
103         }
104     }
105     void doB(int j) {
106         if(j) {
107             vis[val[j]] = false;
108             doB(last[j]);
109         }
110     }
111     void _find(char* T) {
112         int n = strlen(T);
113         int j = 0;
114         for(int i = 0; i < n; i++) {
115             int c = idx(T[i]);
116             while(j && !ch[j][c]) j = f[j];
117             j = ch[j][c];
118             if(val[j])
119                 doA(j);
120             if(val[last[j]])
121                 doB(last[j]);
122         }
123     }
124     void getFail() {
125         queue<int> q;
126         f[0] = 0;
127         for(int c = 0; c < SIGMA_SIZE; c++) {
128             int u = ch[0][c];
129             if(u) {
130                 f[u] = 0;
131                 q.push(u);
132                 last[u] = 0;
133             }
134         }
135         while(!q.empty()) {
136             int r = q.front();
137             q.pop();
138             for(int c = 0; c < SIGMA_SIZE; c++) {
139                 int u = ch[r][c];
140                 if(!u) continue;
141                 q.push(u);
142                 int v = f[r];
143                 while(v && !ch[v][c]) v = f[v];
144                 f[u] = ch[v][c];
145                 last[u] = val[f[u]] ? f[u] : last[f[u]];
146             }
147         }
148     }
149     void delout(char* tmp){
150         int u = 0, n = strlen(tmp);
151         for(int i = 0; i < n - 1; i++) {
152             int c = idx(tmp[i]);
153             u = ch[u][c];
154             if(val[u])
155                 vis[val[u]] = false;
156         }
157     }
158 };
159
160 AhoCorasickAutomata ac;
161 int main() {
162     int T; sf("%d", &T);
163     REP(cas, T){
164         clr(vis, 0);
165         ac.init(); int n; sf("%d", &n);
166         REP(i, n){
167             sf("%s", ctmp);
168             deal(st[i], ctmp);
169             ac._insert(st[i], i);
170         }
171         ac.getFail();
172         sf("%s", ctmp); deal(text, ctmp);
173         ac._find(text); int cnt = 0;
174         REP(i, n){
175             if(vis[i])
176                 ac.delout(st[i]);
177         }
178         REP(i, n){
179             if(vis[i]){
180                 cnt++;
181             }
182         }
183         pf("%d\n", cnt);
184     }
185     return 0;
186 }

POJ 4052 AC自动机,布布扣,bubuko.com

时间: 2024-11-08 17:26:25

POJ 4052 AC自动机的相关文章

poj 2778 AC自动机 + 矩阵快速幂

// poj 2778 AC自动机 + 矩阵快速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就可以得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自动机有一些特别,根节点是为空串,然而 // 每走一步的时候,如果没法走了,这时候,不一定是回到根 // 节点,因为有可能单个的字符时病毒,这样

poj 2778 AC自动机与矩阵连乘

http://poj.org/problem?id=2778 Description It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may

POJ 2778 AC自动机+矩阵幂 不错的题

http://poj.org/problem?id=2778 有空再重新做下,对状态图的理解很重要 题解: http://blog.csdn.net/morgan_xww/article/details/7834801 另外做了矩阵幂的模板: //ac.sz是矩阵的大小 void mulmtr(long long x[MAXNODE][MAXNODE],long long y[MAXNODE][MAXNODE])//y=x*y { ll tmp[MAXNODE][MAXNODE]; for(in

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而

POJ 2896 AC自动机 or 暴力

DESCRIPTION :大意是说.给你n个代表病毒的字符串.m个表示网站的字符串.让你计算有多少个网站被病毒感染了.被那些病毒感染了. 刚开始就想暴力.然而,忽略了条件:每个网站最多有三个病毒.于是.TLE了.于是换AC 自动机.于是MLE了.于是把最大的结构体指针数组换成队列.用时间来换空间.23333 应该注意结构体的初始化是必须的. 附代码:AC 自动机: #include<stdio.h> #include<string.h> #include<iostream&g

poj 2778 AC自动机构建有向图 + 邻接矩阵快速幂

Problem: 给你m个病毒串,求指定长度n且不含病毒串作为子串的字符串一共有多少种. Analyse: 用AC自动机构建L个状态节点,每个节点的end标记记录是否在这里形成病毒串. 这里有个核心就是,如果当前后缀的子后缀(也就是它的fail指针指向的地方)是病毒串的话, 那么它就是病毒串. 然后根据这个AC自动机的L个节点来建立有向图的邻接矩阵B,B[i][j]代表从i到j状态的路径数量. B[0][j]代表的是从初始状态,还没有任何字符的时候转移到j状态,因为根节点0就是没有任何限制. 然

POJ 1204 AC自动机

点击打开链接 题意:给个L*C的字符串矩阵,W个询问,对每个询问输出这个串第一次出现的位置及方向,共有8个方向,用A~H表示 思路:用AC自动机进行快速匹配,细节处理特别多,不看题解的话应该会WA很多次,还有一个处理的非常巧妙地地方,就是我们要输出第一次出现的位置,而AC自动机不能回溯,所以将串反着构造进字典树里,真是神犇,然后方向设置时也反着就可以了 #include <stdio.h> #include <string.h> #include <stdlib.h>

DNA Sequence POJ - 2778 AC 自动机 矩阵乘法

定义重载运算的时候一定要将矩阵初始化,因为这个调了一上午...... Code: #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #define maxn 100000 typedef long long ll; using namespace std; void setIO(string a){ freopen((a+

poj 1699 Best Sequence(AC自动机+状压DP)

题目链接:poj 1699 Best Sequence 题目大意:给定N个DNA序列,问说最少多长的字符串包含所有序列. 解题思路:AC自动机+状压DP,先对字符串构造AC自动机,然后在dp[s][i]表示匹配了s,移动到节点i时候的最短步数. #include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include &