题目大意:

给定一个字符串,接下来再给n个字符串,求原字符串中含有多少个当前给定字符串的循环同构体的字符串的个数

以初始字符串构建后缀自动机,在自动机上前进的时候,比如当前需要匹配的字符串为aba,到达某个状态点S

我们所希望知道的所有aba出现的次数,因为aba最终到达的是点S,其实可以理解为整个后缀自动机通过f(父指针)形成了一棵后缀树

而这个S是后缀树上的叶子节点,那么上方所有的父亲节点都包含这个S,我们只需要找到最顶端的能达到aba状态的根节点,在根状态上记录其下方出现此后缀总共出现的个数

那么首先将后缀自动机拓扑排序,然后节点逆向访问,不断更新父亲节点的信息,用节点上的cnt变量记录当前节点作为根节点时所能得到的后缀的总个数

对于每个当前每个给定的字符串,因为要求循环同构,那么再连接一个相同的字符串在其后方,然后正常在后缀自动机上跑,当匹配到的长度大于len时,说明这个字符串中包含了循环同构体,我们就要不断逆向通过父亲回溯到根节点,这个根节点表示所能达到的长度尽可能小却仍旧大于等于len即可,因为这样的点是当前匹配所有作为大于len的后缀的节点的祖先。然后通过当前节点的flag标记判断当前节点是否被访问过来获取其中的cnt

 #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std; #define N 1000010
#define ll long long
struct SamNode{
SamNode *son[] , *f;
int l , cnt , flag;
void init(){
for(int i= ; i< ; i++) son[i] = NULL;
f=NULL;
l = flag = cnt = ;
}
}sam[N<<] , *root , *last , *b[N<<]; int cnt , n , num[N];
char s[N] , str[N]; void add(int x)
{
SamNode *p = &sam[++cnt] , *jp = last;
p->l = jp->l+ ;
last = p;
for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
if(!jp) p->f = root;
else{
if(jp->l+ == jp->son[x]->l) p->f = jp->son[x];
else{
SamNode *r = &sam[++cnt] , *q = jp->son[x];
*r = *q;
r->l = jp->l+;
p->f = q->f = r;
for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
}
}
} void solve()
{
scanf("%d" , &n);
for(int mark= ; mark<=n ; mark++){
scanf("%s" , str);
int len = strlen(str) , ret = ;
ll ans = ;
SamNode *cur = root;
for(int i= ; i<*len ; i++){
int x = (i>=len?str[i-len]:str[i])-'a';
if(cur->son[x]){
cur = cur->son[x];
ret++;
}
else{
while(cur && !cur->son[x]) cur = cur->f;
if(!cur) cur=root , ret=;
else{
ret = cur->l+;
cur=cur->son[x];
}
}
while(cur->f&&cur->f->l>=len){
cur = cur->f;
ret = cur->l;
}
if(ret>=len && cur->flag!=mark) cur->flag=mark , ans= ans+cur->cnt;
}
printf("%I64d\n" , ans);
}
} int main()
{
// freopen("a.in" , "r", stdin);
scanf("%s" , s);
int len = strlen(s);
sam[].init();
root = last = &sam[cnt=];
for(int i= ; i<len ; i++) add(s[i]-'a');
for(int i= ; i<=cnt ; i++) num[sam[i].l]++;
for(int i= ; i<=len ; i++) num[i] += num[i-];
for(int i= ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];
SamNode *cur = root;
for(int i= ; i<len ; i++){
cur = cur->son[s[i]-'a'];
cur->cnt++;
}
for(int i=cnt ; i> ; i--) b[i]->f->cnt+=b[i]->cnt , b[i]->flag=;
solve();
return ;
}

Codeforces 235C的更多相关文章

  1. Codeforces 235C. Cyclical Quest

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

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

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

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

    [题目链接] http://codeforces.com/contest/235/problem/C [题目大意] 给出一个字符串,给出一些子串,问每个子串分别在母串中圆环匹配的次数,圆环匹配的意思是 ...

  4. Codeforces 235C Cyclical Quest 字符串 SAM KMP

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF235C.html 题目传送门 -  CF235C 题意 给定一个字符串 $s$ ,多组询问,每组询问的形式为 ...

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

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

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

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

  7. Cyclical Quest CodeForces - 235C 后缀自动机

    题意: 给出一个字符串,给出一些子串,问每个子串分别在母串中圆环匹配的次数, 圆环匹配的意思是将该子串拆成两段再首位交换相接的串和母串匹配,比 如aaab变成baaa,abaa,aaba再进行匹配. ...

  8. 后缀自动机(SAM)

    *在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符 ...

  9. 后缀自己主动机(SAM)学习指南

    *在学习后缀自己主动机之前须要熟练掌握WA自己主动机.RE自己主动机与TLE自己主动机* 什么是后缀自己主动机 后缀自己主动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂 ...

随机推荐

  1. C++——友元、异常和其他

    一.友元 类并非只能拥有友元函数,也可以将类作为友元.在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员.另外,也可以做更严格的限制,只将特定的成员函数指定为另一个类的友元.哪些函数. ...

  2. Mybatis3+Spring4+SpringMVC4 整合

    首先在整合这个框架的时候,想想其一般的步骤是怎样的,先有个步骤之后,不至于在后面的搞混了,这样在整合的时候也比较清晰些. 然后我们就细细的一步一步来整合. 1  创建一个Web项目. 2  导入Myb ...

  3. RT-thread学习笔记(一)

    我的基础:能在现有C程序下做些修改,不会移植,不会写驱动,很难从头到尾自己写程序. RT-thread基础:之前看了一点rtthread_manual.zh.pdf(即RT-thread使用手册),发 ...

  4. STM8s窗口看门狗

    看看窗口看门狗的框图 从图里看出产生复位信号有2个方式: 1 WDGCR寄存器的T6 由1变0,也就是从此寄存器的值从0x40变成0x3F会产生复位信号: 2 当寄存器WDGCR的值大于WDGWR的时 ...

  5. Unity3D研究院编辑器之不实例化Prefab获取删除更新组件(十五)

    http://www.xuanyusong.com/archives/3727 感谢楼下的牛逼回复更正一下,我表示我也是才知道.. 其实不需要实例化也能查找,你依然直接用GetComponentsIn ...

  6. css3属性 transition transform

    1.transition 译:过渡,转变 可以设置过渡属性 transition: property duration timing-function delay; transition-proper ...

  7. Python 练习 31

    则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式. re 模块使 Python 语 ...

  8. 《javascript高级程序设计》 第25章 新兴的API

    25.1 requestAnimationFrame() 25.1.1 早期动画循环 25.1.2 循环间隔的问题 25.1.3 mozRequestAnimation-Frame.webkitReq ...

  9. 20150206读书笔记<深入理解计算机系统>

    ●第一章 C是系统级编程的首选.C++显示支持抽象,属于应用级程序设计语言. 简单例子: 一个典型系统的硬件组成: 存储器的层次结构: 注:存储器层次结构的设计思想是,该层存储器作为下一层存储器的高速 ...

  10. C++继承与派生(原理归纳)

    1.   C++继承与java不同,java遵循单继承,但java的接口为其不足做了很好的弥补了. C++则是灵活的多,为多继承.即一个C++类可以同时继承N个类的属性. 2. 对于继承方式 : 有三 ...