Cyclical Quest CodeForces - 235C 后缀自动机
题意:
给出一个字符串,给出一些子串,问每个子串分别在母串中圆环匹配的次数,
圆环匹配的意思是将该子串拆成两段再首位交换相接的串和母串匹配,比
如aaab变成baaa,abaa,aaba再进行匹配。
题解:
如何求出所有的循环串出现的次数呢?
先将S串放入后缀自动机
把查询串扩大一倍,然后在后缀自动机上去匹配,
只要匹配长度大于子串长度小于2倍子串长度的,必然对应这一种循环串
记录一下
- // 每个节点子串出现的次数
- 统计答案即可
- #include <set>
- #include <map>
- #include <stack>
- #include <queue>
- #include <cmath>
- #include <ctime>
- #include <cstdio>
- #include <string>
- #include <vector>
- #include <cstring>
- #include <iostream>
- #include <algorithm>
- #include <unordered_map>
- #define pi acos(-1.0)
- #define eps 1e-9
- #define fi first
- #define se second
- #define rtl rt<<1
- #define rtr rt<<1|1
- #define bug printf("******\n")
- #define mem(a, b) memset(a,b,sizeof(a))
- #define name2str(x) #x
- #define fuck(x) cout<<#x" = "<<x<<endl
- #define sfi(a) scanf("%d", &a)
- #define sffi(a, b) scanf("%d %d", &a, &b)
- #define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
- #define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
- #define sfL(a) scanf("%lld", &a)
- #define sffL(a, b) scanf("%lld %lld", &a, &b)
- #define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
- #define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
- #define sfs(a) scanf("%s", a)
- #define sffs(a, b) scanf("%s %s", a, b)
- #define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
- #define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
- #define FIN freopen("../in.txt","r",stdin)
- #define gcd(a, b) __gcd(a,b)
- #define lowbit(x) x&-x
- #define IO iOS::sync_with_stdio(false)
- using namespace std;
- typedef long long LL;
- typedef unsigned long long ULL;
- const ULL seed = ;
- const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
- const int maxm = 8e6 + ;
- const int INF = 0x3f3f3f3f;
- const int mod = 1e9 + ;
- const int maxn = ;
- char s[maxn];
- int Q;
- struct Suffix_Automaton {
- int last, tot, nxt[maxn << ][], fail[maxn << ];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号
- int len[maxn << ];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]])
- int sa[maxn << ], c[maxn << ];
- int sz[maxn << ];// 被后缀链接的个数,方便求节点字符串的个数
- LL num[maxn << ];// 该状态子串的数量
- LL maxx[maxn << ];// 长度为x的子串出现次数最多的子串的数目
- LL sum[maxn << ];// 该节点后面所形成的自字符串的总数
- LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度
- int X[maxn << ], Y[maxn << ]; // Y表示排名为x的节点,X表示该长度前面还有多少个
- int minn[maxn << ], mx[maxn << ];//minn[i]表示多个串在后缀自动机i节点最长公共子串,mx[i]表示单个串的最长公共子串
- void init() {
- tot = last = ;
- fail[] = len[] = ;
- for (int i = ; i < ; i++) nxt[][i] = ;
- }
- void extend(int c) {
- int u = ++tot, v = last;
- len[u] = len[v] + ;
- num[u] = ;
- for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u;
- if (!v) fail[u] = , sz[]++;
- else if (len[nxt[v][c]] == len[v] + ) fail[u] = nxt[v][c], sz[nxt[v][c]]++;
- else {
- int now = ++tot, cur = nxt[v][c];
- len[now] = len[v] + ;
- memcpy(nxt[now], nxt[cur], sizeof(nxt[cur]));
- fail[now] = fail[cur];
- fail[cur] = fail[u] = now;
- for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now;
- sz[now] += ;
- }
- last = u;
- //return len[last] - len[fail[last]];//多添加一个子串所产生不同子串的个数
- }
- void get_num() {// 每个节点子串出现的次数
- for (int i = ; i <= tot; i++) X[len[i]]++;
- for (int i = ; i <= tot; i++) X[i] += X[i - ];
- for (int i = ; i <= tot; i++) Y[X[len[i]]--] = i;
- for (int i = tot; i >= ; i--) num[fail[Y[i]]] += num[Y[i]];
- }
- void get_maxx(int n) {// 长度为x的子串出现次数最多的子串的数目
- get_num();
- for (int i = ; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]);
- }
- void get_sum() {// 该节点后面所形成的自字符串的总数
- get_num();
- for (int i = tot; i >= ; i--) {
- sum[Y[i]] = ;
- for (int j = ; j <= ; j++)
- sum[Y[i]] += sum[nxt[Y[i]][j]];
- }
- }
- void get_subnum() {//本质不同的子串的个数
- subnum = ;
- for (int i = ; i <= tot; i++) subnum += len[i] - len[fail[i]];
- }
- void get_sublen() {//本质不同的子串的总长度
- sublen = ;
- for (int i = ; i <= tot; i++) sublen += 1LL * (len[i] + len[fail[i]] + ) * (len[i] - len[fail[i]]) / ;
- }
- void get_sa() { //获取sa数组
- for (int i = ; i <= tot; i++) c[len[i]]++;
- for (int i = ; i <= tot; i++) c[i] += c[i - ];
- for (int i = tot; i >= ; i--) sa[c[len[i]]--] = i;
- }
- void match(char s[]) {//多个串的最长公共子串
- mem(mx, );
- int n = strlen(s), p = , maxlen = ;
- for (int i = ; i < n; i++) {
- int c = s[i] - 'a';
- if (nxt[p][c]) p = nxt[p][c], maxlen++;
- else {
- for (; p && !nxt[p][c]; p = fail[p]);
- if (!p) p = , maxlen = ;
- else maxlen = len[p] + , p = nxt[p][c];
- }
- mx[p] = max(mx[p], maxlen);
- }
- for (int i = tot; i; i--)
- mx[fail[i]] = max(mx[fail[i]], min(len[fail[i]], mx[i]));
- for (int i = tot; i; i--)
- if (minn[i] == - || minn[i] > maxx[i]) minn[i] = mx[i];
- }
- void get_kth(int k) {//求出字典序第K的子串
- int pos = , cnt;
- string s = "";
- while (k) {
- for (int i = ; i <= ; i++) {
- if (nxt[pos][i] && k) {
- cnt = nxt[pos][i];
- if (sum[cnt] < k) k -= sum[cnt];
- else {
- k--;
- pos = cnt;
- s += (char) (i + 'a');
- break;
- }
- }
- }
- }
- cout << s << endl;
- }
- int vis[maxn << ];
- void solve(int lenlen, int id) {
- int maxlen = , p = , ans = ;
- for (int i = ; i <= lenlen * ; i++) {
- int c = s[i] - 'a';
- if (nxt[p][c]) maxlen++, p = nxt[p][c];
- else {
- for (; p && !nxt[p][c]; p = fail[p]);
- if (p == ) p = , maxlen = ;
- else maxlen = len[p] + , p = nxt[p][c];
- }
- if (i >= lenlen && maxlen >= lenlen) {
- int temp = p;
- while (temp && !(len[fail[temp]] + <= lenlen && len[temp] >= lenlen))temp = fail[temp];
- if (!temp) temp = ;
- if (vis[temp] != id) vis[temp] = id, ans += num[temp];
- }
- }
- printf("%d\n", ans);
- }
- } sam;
- int main() {
- #ifndef ONLINE_JUDGE
- FIN;
- #endif
- sam.init();
- sfs(s + );
- int n = strlen(s + );
- for (int i = ; i <= n; i++) sam.extend((s[i] - 'a'));
- sam.get_num();
- sfi(Q);
- for (int i = ; i <= Q; i++) {
- sfs(s + );
- int len = strlen(s + );
- for (int i = ; i <= len; i++) s[i + len] = s[i];
- s[ * len + ] = '\0';
- //fuck(s + 1);
- sam.solve(len, i);
- }
- #ifndef ONLINE_JUDGE
- cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
- #endif
- return ;
- }
Cyclical Quest CodeForces - 235C 后缀自动机的更多相关文章
- Cyclical Quest CodeForces - 235C (后缀自动机)
Cyclical Quest \[ Time Limit: 3000 ms\quad Memory Limit: 524288 kB \] 题意 给出一个字符串为 \(s\) 串,接下来 \(T\) ...
- Match & Catch CodeForces - 427D 后缀自动机水题
题意: 给出两个字符串a,b,求一个字符串,这个字符串是a和b的子串, 且只在a,b中出现一次,要求输出这个字符串的最小长度. 题解: 将a串放入后缀自动机中,然后记录一下每个节点对应的子串出现的次数 ...
- cf 235C 后缀自动机
题目大意 给定字符串\(S\)与\(n<=10^5\)个串\(x_1,x_2...x_n\)(总长\(\le10^6\)) 对于每个\(x_i\),输出有多少个\(S\)的子串与\(x_i\)循 ...
- Codeforces 235C Cyclical Quest - 后缀自动机
Some days ago, WJMZBMR learned how to answer the query "how many times does a string x occur in ...
- 【CodeForces - 235C】Cyclical Quest 【后缀自动机】
题意 给出一个字符串s1和q个询问,每个询问给出一个字符串s2,问这个询问的字符串的所有不同的周期串在s1中出现的次数的和. 分析 对于s1建后缀自动机.对于询问的每个字符串s2,我们按照处理循环串的 ...
- 【Codeforces235C】Cyclical Quest 后缀自动机
C. Cyclical Quest time limit per test:3 seconds memory limit per test:512 megabytes input:standard i ...
- 【CF235C】Cyclical Quest(后缀自动机)
[CF235C]Cyclical Quest(后缀自动机) 题面 洛谷 题解 大致翻译: 给定一个串 然后若干组询问 每次也给定一个串 这个串可以旋转(就是把最后一位丢到最前面这样子) 问这个串以及其 ...
- Codeforces 235C. Cyclical Quest
传送门 写的时候挺蛋疼的. 刚开始的时候思路没跑偏,无非就是建个SAM然后把串开两倍然后在SAM上跑完后统计贡献.但是卡在第二个样例上就是没考虑相同的情况. 然后开始乱搞,发现会出现相同串的只有可能是 ...
- Codeforces 452E Three Strings(后缀自动机)
上学期很认真地学了一些字符串的常用工具,各种 suffix structre,但是其实对后缀自动机这个部分是理解地不太透彻的,以致于看了师兄A这题的代码后,我完全看不懂,于是乎重新看回一些学习后缀自动 ...
随机推荐
- 力扣算法——133.CloneGraph【M】
Given a reference of a node in a connected undirected graph, return a deep copy (clone) of the graph ...
- Python系列——常用第三方库
幕布视图(更加方便.明了):https://mubu.com/doc/AqoVZ8x6m0 参考文献:嵩天老师的Python讲义 模块 定义 计算机在开发过程中,代码越写越多,也就越难以维护,所以为了 ...
- python之命名元组的好处
collections.namedtuple() 命名元组的一个主要用途是将你的代码从下标操作中解脱出来举例使用 # 使用 from collections import namedtuple Sub ...
- springboot集成redis报错-ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
当使用Springboot 2.0以上版本集成redis的时候遇到报错信息如下: Application run failed org.springframework.beans.factory.Un ...
- OpenGL学习——搭建OpenGL运行环境——生成一个空白视口——基于GLFW&GLEW
最近学习OpenGL,读OpenGL宝典一头蒙,各种gl函数不知所云.逐决定先搭OpenGL运行环境,详细如下. 1.首先OpenGL是什么?是一个标准规范,是一个巨大的状态机,并无具体实现,大多数实 ...
- 循环神经网络(Recurrent Neural Network)
传统的神经网络模型,隐藏层的节点之间是无连接的,如下图所示. 而循环神经网络隐藏层的节点之间有连接,主要用于对序列数据进行分类.预测等处理.有连接意味着需要接受信息,这种网络通常用来对序列数据进行处理 ...
- io.File+递归
import java.io.File ; import java.io.IOException ; public class FileDemo11{ public static void main( ...
- FTP的PORT和PASV的连接方式以及数据连接端口号计算
FTP的PORT和PASV的连接方式以及数据连接端口号计算 PORT(自动)方法的连接途中是: 客户端向服务器的FTP端口(原始是21)发送连接请求,服务器领受连接,建立一条command链路. ...
- 用javascript插入<style>样式
function addCSS(cssText){ var style = document.createElement('style'), //创建一个style元素 head = document ...
- 2018.12.26 考试(哈希,二分,状压dp)
T1 传送门 解题思路 发现有一个限制是每个字母都必须相等,那么就可以转化成首尾的差值相等,然后就可以求出\(k-1\)位的差值\(hash\)一下.\(k\)为字符集大小,时间复杂度为\(O(nk) ...