题目大意

给定一个模板串, 再给出\(n\)个询问, 询问每一个串的循环串总共在原串中出现了多少次.

循环串: 比如说有\(str[] = \{ABCD\}\), 则其循环串有\(\{ABCD\}, \{BCDA\}, \{CDAB\}, \{DABC\}\), 共\(len\)个.

题解

把每一个串复制一遍放在原串后面: \(\{ABCD\} \to \{ABCDABC\}\), 放入原串的后缀自动机中匹配. 在匹配时, 假如下一位无法匹配, 则跳suffix link; 假如即使跳了suffix link, 最大长度\(len(suffix)\)仍然大于等于原串长度, 则也跳suffix link(相当于砍掉多余的部分).

放入SAM前要先跑一次KMP去循环节.

#include <cstdio>
#include <cstring>
#include <vector> const int LEN = (int)1e6; struct suffixAutomaton
{
struct state
{
state *suc[26], *pre;
int len;
int sz, tg;
std::vector<state*> bck; inline state()
{
for(int i = 0; i < 26; ++ i)
suc[i] = NULL;
pre = NULL;
sz = 1;
bck.clear();
tg = 0;
}
}; state *rt, *lst; inline void insert(int c)
{
state *u = new state;
u->len = lst->len + 1;
for(; lst != NULL && lst->suc[c] == NULL; lst->suc[c] = u, lst = lst->pre);
if(lst == NULL)
u->pre = rt;
else
{
state *p = lst->suc[c];
if(p->len == lst->len + 1)
u->pre = p;
else
{
state *q = new state;
*q = *p;
q->len = lst->len + 1, q->sz = 0;
p->pre = u->pre = q;
for(; lst != NULL && lst->suc[c] == p; lst->suc[c] = q, lst = lst->pre);
}
}
lst = u;
} void DFS(state *u)
{
u->tg = 1;
if(u->pre != NULL)
u->pre->bck.push_back(u);
for(int i = 0; i < 26; ++ i)
if(u->suc[i] != NULL && ! u->suc[i]->tg)
DFS(u->suc[i]);
} void get(state *u)
{
for(std::vector<state*>::iterator p = u->bck.begin(); p != u->bck.end(); ++ p)
get(*p), u->sz += (*p)->sz;
} inline void build(char *str, int len)
{
lst = rt = new state;
rt->len = 0;
for(int i = 0; i < len; ++ i)
insert(str[i] - 'a');
DFS(rt);
get(rt);
} inline int match(char *str, int len, int cir)
{
state *u = rt;
int cur = 0;
long long ans = 0;
for(int i = 0; i < len + cir - 1; ++ i)
{
for(; u != rt && u->suc[str[i] - 'a'] == NULL; cur = u->pre->len, u = u->pre);
if(u->suc[str[i] - 'a'] != NULL)
u = u->suc[str[i] - 'a'], ++ cur;
for(; u != rt && u->pre->len >= len; cur = u->pre->len, u = u->pre);
if(cur >= len)
ans += u->sz;
}
return ans;
}
}SAM; int main()
{
#ifndef ONLINE_JUDGE
freopen("CF235C.in", "r", stdin);
#endif
static char str[LEN];
scanf("%s", str);
int len = strlen(str);
SAM.build(str, len);
int n;
scanf("%d\n", &n);
for(int i = 0; i < n; ++ i)
{
static char str[LEN << 1];
scanf("%s", str);
int len = strlen(str);
static int nxt[LEN];
nxt[0] = -1;
int p = nxt[0];
for(int i = 1; i < len; ++ i)
{
for(; ~ p && str[i] ^ str[p + 1]; p = nxt[p]);
nxt[i] = str[i] == str[p + 1] ? ++ p : p;
}
int cir = len % (len - nxt[len - 1] - 1) == 0 ? len - nxt[len - 1] - 1 : len;
for(int i = 0; i < cir; ++ i)
str[i + len] = str[i];
printf("%d\n", SAM.match(str, len, cir));
}
}

最新文章

  1. LeetCode:N-Queens I II(n皇后问题)
  2. C# 的一些语法特性
  3. 树莓派 config.txt
  4. 使用 IntraWeb (39) - THttpRequest、THttpReply
  5. spring hadoop 访问hbase入门
  6. Function---hdu5875(大连网选,区间连续求余)
  7. Intel微处理器学习笔记(五) 中断
  8. Chrome远程调试Android上Chrome的页面
  9. [Caffe] ubuntu14.04下使用OpenBLAS加速Caffe
  10. Python笔记&#183;第四章—— 细数Python中的数据类型以及他们的方法
  11. 复制粘贴之不带插件的jquery
  12. 关于Unity的协程
  13. Python打开新世界的大门-入门篇1
  14. Oracle之数组
  15. Python_内置函数之max
  16. Git换行符是如何精确控制的
  17. 【cocos2d-js官方文档】事件分发监听机制(摘录)
  18. Tomcat学习总结(4)——基于Tomcat7、Java、WebSocket的服务器推送聊天室
  19. Linux命令(九)比较文件差异 diff
  20. USACO 2.3.4 Money Systems 货币系统(完全背包)

热门文章

  1. 评估后Vista时代系统内核模式安全性
  2. luogu4001 [BJOI2006]狼抓兔子
  3. provider:命名管道提供程序,error:40 - 无法打开到SQL Server的连接 (Microsoft
  4. Leetcode4---&gt;求两个排序数组的中位数
  5. SpringMVC 页面传递参数到controller的五种方式
  6. 大数据学习——sparkSql对接hive
  7. Flask_单例模式
  8. linux快速查看同局域网的其他在线主机
  9. javascript学习笔记 - 面向对象 理解对象
  10. ibatis 动态SQL