题意:

给出一个字符串,给出一些子串,问每个子串分别在母串中圆环匹配的次数,

圆环匹配的意思是将该子串拆成两段再首位交换相接的串和母串匹配,比

如aaab变成baaa,abaa,aaba再进行匹配。

题解:

如何求出所有的循环串出现的次数呢?

先将S串放入后缀自动机

把查询串扩大一倍,然后在后缀自动机上去匹配,

只要匹配长度大于子串长度小于2倍子串长度的,必然对应这一种循环串

记录一下

  1. // 每个节点子串出现的次数
  2.  
  3. 统计答案即可
  1. #include <set>
  2. #include <map>
  3. #include <stack>
  4. #include <queue>
  5. #include <cmath>
  6. #include <ctime>
  7. #include <cstdio>
  8. #include <string>
  9. #include <vector>
  10. #include <cstring>
  11. #include <iostream>
  12. #include <algorithm>
  13. #include <unordered_map>
  14.  
  15. #define pi acos(-1.0)
  16. #define eps 1e-9
  17. #define fi first
  18. #define se second
  19. #define rtl rt<<1
  20. #define rtr rt<<1|1
  21. #define bug printf("******\n")
  22. #define mem(a, b) memset(a,b,sizeof(a))
  23. #define name2str(x) #x
  24. #define fuck(x) cout<<#x" = "<<x<<endl
  25. #define sfi(a) scanf("%d", &a)
  26. #define sffi(a, b) scanf("%d %d", &a, &b)
  27. #define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
  28. #define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
  29. #define sfL(a) scanf("%lld", &a)
  30. #define sffL(a, b) scanf("%lld %lld", &a, &b)
  31. #define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
  32. #define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
  33. #define sfs(a) scanf("%s", a)
  34. #define sffs(a, b) scanf("%s %s", a, b)
  35. #define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
  36. #define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
  37. #define FIN freopen("../in.txt","r",stdin)
  38. #define gcd(a, b) __gcd(a,b)
  39. #define lowbit(x) x&-x
  40. #define IO iOS::sync_with_stdio(false)
  41.  
  42. using namespace std;
  43. typedef long long LL;
  44. typedef unsigned long long ULL;
  45. const ULL seed = ;
  46. const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
  47. const int maxm = 8e6 + ;
  48. const int INF = 0x3f3f3f3f;
  49. const int mod = 1e9 + ;
  50. const int maxn = ;
  51. char s[maxn];
  52. int Q;
  53.  
  54. struct Suffix_Automaton {
  55. int last, tot, nxt[maxn << ][], fail[maxn << ];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号
  56. int len[maxn << ];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]])
  57. int sa[maxn << ], c[maxn << ];
  58. int sz[maxn << ];// 被后缀链接的个数,方便求节点字符串的个数
  59. LL num[maxn << ];// 该状态子串的数量
  60. LL maxx[maxn << ];// 长度为x的子串出现次数最多的子串的数目
  61. LL sum[maxn << ];// 该节点后面所形成的自字符串的总数
  62. LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度
  63. int X[maxn << ], Y[maxn << ]; // Y表示排名为x的节点,X表示该长度前面还有多少个
  64. int minn[maxn << ], mx[maxn << ];//minn[i]表示多个串在后缀自动机i节点最长公共子串,mx[i]表示单个串的最长公共子串
  65. void init() {
  66. tot = last = ;
  67. fail[] = len[] = ;
  68. for (int i = ; i < ; i++) nxt[][i] = ;
  69. }
  70.  
  71. void extend(int c) {
  72. int u = ++tot, v = last;
  73. len[u] = len[v] + ;
  74. num[u] = ;
  75. for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u;
  76. if (!v) fail[u] = , sz[]++;
  77. else if (len[nxt[v][c]] == len[v] + ) fail[u] = nxt[v][c], sz[nxt[v][c]]++;
  78. else {
  79. int now = ++tot, cur = nxt[v][c];
  80. len[now] = len[v] + ;
  81. memcpy(nxt[now], nxt[cur], sizeof(nxt[cur]));
  82. fail[now] = fail[cur];
  83. fail[cur] = fail[u] = now;
  84. for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now;
  85. sz[now] += ;
  86. }
  87. last = u;
  88. //return len[last] - len[fail[last]];//多添加一个子串所产生不同子串的个数
  89. }
  90.  
  91. void get_num() {// 每个节点子串出现的次数
  92. for (int i = ; i <= tot; i++) X[len[i]]++;
  93. for (int i = ; i <= tot; i++) X[i] += X[i - ];
  94. for (int i = ; i <= tot; i++) Y[X[len[i]]--] = i;
  95. for (int i = tot; i >= ; i--) num[fail[Y[i]]] += num[Y[i]];
  96. }
  97.  
  98. void get_maxx(int n) {// 长度为x的子串出现次数最多的子串的数目
  99. get_num();
  100. for (int i = ; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]);
  101. }
  102.  
  103. void get_sum() {// 该节点后面所形成的自字符串的总数
  104. get_num();
  105. for (int i = tot; i >= ; i--) {
  106. sum[Y[i]] = ;
  107. for (int j = ; j <= ; j++)
  108. sum[Y[i]] += sum[nxt[Y[i]][j]];
  109. }
  110. }
  111.  
  112. void get_subnum() {//本质不同的子串的个数
  113. subnum = ;
  114. for (int i = ; i <= tot; i++) subnum += len[i] - len[fail[i]];
  115. }
  116.  
  117. void get_sublen() {//本质不同的子串的总长度
  118. sublen = ;
  119. for (int i = ; i <= tot; i++) sublen += 1LL * (len[i] + len[fail[i]] + ) * (len[i] - len[fail[i]]) / ;
  120. }
  121.  
  122. void get_sa() { //获取sa数组
  123. for (int i = ; i <= tot; i++) c[len[i]]++;
  124. for (int i = ; i <= tot; i++) c[i] += c[i - ];
  125. for (int i = tot; i >= ; i--) sa[c[len[i]]--] = i;
  126. }
  127.  
  128. void match(char s[]) {//多个串的最长公共子串
  129. mem(mx, );
  130. int n = strlen(s), p = , maxlen = ;
  131. for (int i = ; i < n; i++) {
  132. int c = s[i] - 'a';
  133. if (nxt[p][c]) p = nxt[p][c], maxlen++;
  134. else {
  135. for (; p && !nxt[p][c]; p = fail[p]);
  136. if (!p) p = , maxlen = ;
  137. else maxlen = len[p] + , p = nxt[p][c];
  138. }
  139. mx[p] = max(mx[p], maxlen);
  140. }
  141. for (int i = tot; i; i--)
  142. mx[fail[i]] = max(mx[fail[i]], min(len[fail[i]], mx[i]));
  143. for (int i = tot; i; i--)
  144. if (minn[i] == - || minn[i] > maxx[i]) minn[i] = mx[i];
  145. }
  146.  
  147. void get_kth(int k) {//求出字典序第K的子串
  148. int pos = , cnt;
  149. string s = "";
  150. while (k) {
  151. for (int i = ; i <= ; i++) {
  152. if (nxt[pos][i] && k) {
  153. cnt = nxt[pos][i];
  154. if (sum[cnt] < k) k -= sum[cnt];
  155. else {
  156. k--;
  157. pos = cnt;
  158. s += (char) (i + 'a');
  159. break;
  160. }
  161. }
  162. }
  163. }
  164. cout << s << endl;
  165. }
  166.  
  167. int vis[maxn << ];
  168.  
  169. void solve(int lenlen, int id) {
  170. int maxlen = , p = , ans = ;
  171. for (int i = ; i <= lenlen * ; i++) {
  172. int c = s[i] - 'a';
  173. if (nxt[p][c]) maxlen++, p = nxt[p][c];
  174. else {
  175. for (; p && !nxt[p][c]; p = fail[p]);
  176. if (p == ) p = , maxlen = ;
  177. else maxlen = len[p] + , p = nxt[p][c];
  178. }
  179. if (i >= lenlen && maxlen >= lenlen) {
  180. int temp = p;
  181. while (temp && !(len[fail[temp]] + <= lenlen && len[temp] >= lenlen))temp = fail[temp];
  182. if (!temp) temp = ;
  183. if (vis[temp] != id) vis[temp] = id, ans += num[temp];
  184. }
  185. }
  186. printf("%d\n", ans);
  187. }
  188. } sam;
  189.  
  190. int main() {
  191. #ifndef ONLINE_JUDGE
  192. FIN;
  193. #endif
  194. sam.init();
  195. sfs(s + );
  196. int n = strlen(s + );
  197. for (int i = ; i <= n; i++) sam.extend((s[i] - 'a'));
  198. sam.get_num();
  199. sfi(Q);
  200. for (int i = ; i <= Q; i++) {
  201. sfs(s + );
  202. int len = strlen(s + );
  203. for (int i = ; i <= len; i++) s[i + len] = s[i];
  204. s[ * len + ] = '\0';
  205. //fuck(s + 1);
  206. sam.solve(len, i);
  207. }
  208. #ifndef ONLINE_JUDGE
  209. cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
  210. #endif
  211. return ;
  212. }

Cyclical Quest CodeForces - 235C 后缀自动机的更多相关文章

  1. Cyclical Quest CodeForces - 235C (后缀自动机)

    Cyclical Quest \[ Time Limit: 3000 ms\quad Memory Limit: 524288 kB \] 题意 给出一个字符串为 \(s\) 串,接下来 \(T\) ...

  2. Match & Catch CodeForces - 427D 后缀自动机水题

    题意: 给出两个字符串a,b,求一个字符串,这个字符串是a和b的子串, 且只在a,b中出现一次,要求输出这个字符串的最小长度. 题解: 将a串放入后缀自动机中,然后记录一下每个节点对应的子串出现的次数 ...

  3. cf 235C 后缀自动机

    题目大意 给定字符串\(S\)与\(n<=10^5\)个串\(x_1,x_2...x_n\)(总长\(\le10^6\)) 对于每个\(x_i\),输出有多少个\(S\)的子串与\(x_i\)循 ...

  4. Codeforces 235C Cyclical Quest - 后缀自动机

    Some days ago, WJMZBMR learned how to answer the query "how many times does a string x occur in ...

  5. 【CodeForces - 235C】Cyclical Quest 【后缀自动机】

    题意 给出一个字符串s1和q个询问,每个询问给出一个字符串s2,问这个询问的字符串的所有不同的周期串在s1中出现的次数的和. 分析 对于s1建后缀自动机.对于询问的每个字符串s2,我们按照处理循环串的 ...

  6. 【Codeforces235C】Cyclical Quest 后缀自动机

    C. Cyclical Quest time limit per test:3 seconds memory limit per test:512 megabytes input:standard i ...

  7. 【CF235C】Cyclical Quest(后缀自动机)

    [CF235C]Cyclical Quest(后缀自动机) 题面 洛谷 题解 大致翻译: 给定一个串 然后若干组询问 每次也给定一个串 这个串可以旋转(就是把最后一位丢到最前面这样子) 问这个串以及其 ...

  8. Codeforces 235C. Cyclical Quest

    传送门 写的时候挺蛋疼的. 刚开始的时候思路没跑偏,无非就是建个SAM然后把串开两倍然后在SAM上跑完后统计贡献.但是卡在第二个样例上就是没考虑相同的情况. 然后开始乱搞,发现会出现相同串的只有可能是 ...

  9. Codeforces 452E Three Strings(后缀自动机)

    上学期很认真地学了一些字符串的常用工具,各种 suffix structre,但是其实对后缀自动机这个部分是理解地不太透彻的,以致于看了师兄A这题的代码后,我完全看不懂,于是乎重新看回一些学习后缀自动 ...

随机推荐

  1. linux下安装JMeter(小白教程)

    用windows平台测试时,会受到网络条件的影响,导致测试结果不够准确,尤其是高并发的情况下,需要能够精准的测试请求的响应时长,对于网络的要求更加苛刻.在这样的情况下,可以考虑在linux服务器端安装 ...

  2. 单机zookeeper部署伪集群

    1.zookeeper介绍 ZooKeeper 是一个为分布式应用所设计的分布的.开源的协调服务.分布式的应用可以建立在同步.配置管理.分组和命名等服务的更高级别的实现的基础之上. ZooKeeper ...

  3. Linux 常用指令总结

    一. 与时间有关的参数: 1.find 基本语法参数如下: find [PATH] [option] [action] -mtime n : n为数字,意思为在n天之前的“一天内”被更改过的文件: - ...

  4. Spring Boot集成Mybatis双数据源

    这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源实现数据库的读写分离. 添加依赖 加入Mybatis启动器,这里添加了D ...

  5. 第二章 部署Kubernetes集群准备环境

    一.centos7开机自动联网设置 1.使用root用户登录进入Linux,打开进去终端 2.在终端中输入:cd  /etc/sysconfig/network-scripts 3.ll命令找到目录下 ...

  6. haproxy的代理中继用法

    背景: 现有: 一台baidu/ali/tecent云服务器A(地址为a.a.a.a); 一台VPS B(地址为b.b.b.b), B中搭建有ss,监听端口为8000. 需求: 一:使用A做跳板机访问 ...

  7. 同一子网建立ssh通道,映射到本地

    在办公室有一台机器连入同一子网络,开启jupyter-notebook但是只能在这台机器上访问到,怎样可以在家也可以访问呢? 此时最简单的方法是在本地建立一个ssh通道: 在本地终端中输入 ssh u ...

  8. 59. jdk1.5新特性之----增强for循环

    /*jdk1.5新特性之----增强for循环:底层是一个迭代器 作用:简化迭代器书写格式 使用范围:实现了Iterable接口的对象或者数组对象 格式:    for(变量类型  变量名 :遍历目标 ...

  9. leetcode-162周赛-1253-重构二进制矩阵

    题目描述: 自己的提交: class Solution: def reconstructMatrix(self, upper: int, lower: int, colsum: List[int]) ...

  10. Ecshop商品浏览历史样式修改方法

    想要修改ECSHOP的浏览历史样式,发现 history.lbi 中不能修改. 需要修改的文件:includes\lib_insert.php,找到函数:function insert_history ...