Codeforces Round #146 (Div. 1) C. Cyclical Quest——后缀自动机
2013-08-04 23:56
531 查看
题意:给定一个母串,每次询问一个子串或把子串的前一部分移到末尾形成的串在母串中出现的次数。
处理方法都是很常见的。对询问中的每个子串,设长度为len。复制一份放到其末尾位置并把最后一个字符去掉。再拿这个串和母串的自动机匹配,对于询问串的每一个位置,记录该位置往前能匹配的长度,如果长度大于等于len,则通过pre指针找到从这个位置往前len个字符之间的串在自动机中对应的状态。并将答案加上该状态出现的次数。还要注意,因为复制后的询问串中会有一些长度为len的相同子串出现在不同的位置,那么在匹配的过程中就有可能重复计算,拿我们就在每个状态上加上标记,如果标记过就不再计算。
处理方法都是很常见的。对询问中的每个子串,设长度为len。复制一份放到其末尾位置并把最后一个字符去掉。再拿这个串和母串的自动机匹配,对于询问串的每一个位置,记录该位置往前能匹配的长度,如果长度大于等于len,则通过pre指针找到从这个位置往前len个字符之间的串在自动机中对应的状态。并将答案加上该状态出现的次数。还要注意,因为复制后的询问串中会有一些长度为len的相同子串出现在不同的位置,那么在匹配的过程中就有可能重复计算,拿我们就在每个状态上加上标记,如果标记过就不再计算。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define lng long long using namespace std; const int maxn = 3000000 + 10; int str[maxn], len; struct suffixautomaton { int ch[maxn][30], pre[maxn], val[maxn]; int c[maxn], top[maxn], flag[maxn]; int num[maxn], sz, last; void init() { pre[0] = -1; last = 0; sz = 1; memset(ch[0], 0, sizeof(ch[0])); memset(num, 0, sizeof(num)); memset(flag, 0, sizeof(flag)); } void insert(int x) { int p = last, np = sz++; last = np; memset(ch[np], 0, sizeof(ch[np])); val[np] = val[p] + 1; while(p != -1 && ch[p][x] == 0) { ch[p][x] = np; p = pre[p]; } if(p == -1) pre[np] = 0; else { int q = ch[p][x]; if(val[q] == val[p] + 1) pre[np] = q; else { int nq = sz++; memcpy(ch[nq], ch[q], sizeof(ch[q])); val[nq] = val[p] + 1; pre[nq] = pre[q]; pre[q] = pre[np] = nq; while(p != -1 && ch[p][x] == q) { ch[p][x] = nq; p = pre[p]; } } } } void calc() { memset(c, 0, sizeof(c)); for(int i = 0; i < sz; ++i) c[val[i]] += 1; for(int i = 1; i <= len; ++i) c[i] += c[i - 1]; for(int i = 0; i < sz; ++i) top[--c[val[i]]] = i; for(int i = 0; ; i = ch[i][str[val[i]]]) { num[i] = 1; if(val[i] == len) break; } for(int i = sz - 1; i > 0; --i) num[pre[top[i]]] += num[top[i]]; } lng query(char * s, int c, int tmplen) { lng ans = 0; int u = 0, l = 0; for(int i = 0; s[i]; ++i) { int x = s[i] - 'a'; if(ch[u][x]) { u = ch[u][x]; l++; } else { while(u != -1 && ch[u][x] == 0) u = pre[u]; if(u == -1) u = 0, l = 0; else { l = val[u] + 1; u = ch[u][x]; } } if(l >= tmplen) { int v = u; while(val[pre[v]] >= tmplen) v = pre[v]; if(flag[v] != c) { flag[v] = c; ans += num[v]; } } } return ans; } }sam; char s[maxn]; int main() { scanf("%s", s); len = strlen(s); sam.init(); for(int i = 0; i < len; ++i) { str[i] = s[i] - 'a'; sam.insert(str[i]); } sam.calc(); int q; scanf("%d", &q); while(q--) { scanf("%s", s); int tmp = strlen(s); for(int i = 0; i < tmp - 1; ++i) s[tmp + i] = s[i]; s[2 * tmp - 1] = '\0'; cout << sam.query(s, q + 1, tmp) << "\n"; } return 0; }
相关文章推荐
- Codeforces round 146 C - Cyclical Quest(后缀自动机)
- 字符串(后缀自动机):Codeforces Round #129 (Div. 1) E.Little Elephant and Strings
- Cyclical Quest CodeForces - 235C (后缀自动机 SAM)
- Codeforces Round #146 (Div. 2) C. LCM Challenge
- Codeforces Round #146 (Div. 1) C - Cyclical Quest (后缀自动机SAM)
- Codeforces Round #146 (Div. 1) A. LCM Challenge 水题
- Codeforces Round #244 (Div. 2)D (后缀自己主动机)
- Codeforces Round #404 (Div. 2) D. Anton and School - 2 前缀的后缀、 范德蒙恒等式、容斥
- Codeforces Round #327 (Div. 1) E. Birthday【AC自动机+网络流】
- Codeforces Round #146 (Div. 2) Cyclical Quest 后缀自动机
- Codeforces Round #400 (Div. 1 + Div. 2, combined) C. Molly's Chemicals 区间和、构造、前缀的后缀
- Codeforces Round #380 (Div. 2, Rated, Based on Technocup 2017 - Elimination Round 2)
- Codeforces Round #Pi (Div. 2) E. President and Roads(无向图缩点(有重边)+最短路)
- Codeforces Round #356 (Div. 1)
- Codeforces Round #200 (Div. 2)E
- Codeforces Round #112 (Div. 2) D. Beard Graph
- CF Codeforces Round #162 (Div. 1) A. Escape from Stones
- Codeforces Round #170 (Div. 2)---C. Learning Languages(并查集)
- Codeforces Round #313 (Div. 2) 560C Gerald's Hexagon(脑洞)
- Codeforces Round #FF (Div. 二):C. DZY Loves Sequences