题目大意:

给定一个字符串,接下来再给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. iOS项目中的version和build

    Version在plist文件中的key是“CFBundleShortVersionString”,标识应用程序的发布版本号,和AppStore上的版本号保持一致.该版本的版本号是三个分隔的整数组成的 ...

  2. HTML5地理位置概述和地理位置对象的详解

    一.地理位置 经度  :   南北极的连接线 纬度  :   东西连接的线   二.位置信息从何而来 IP地址 GPS全球定位系统 Wi-Fi无线网络 基站         三.地理位置对象(navi ...

  3. lftp

    linux安装FTP工具 lftp及使用教程 来源:网络 发布时间:2013-05-24 15:21 字体:[大  中  小] 点击2510次 linux下可以直接通过FTP命令进行ftp上传下载,不 ...

  4. POJ 1218

    题目描述看着就乐了,死板得只按着题意来写了ps: tequi是escape的方言版.. #include <iostream> using namespace std; int main( ...

  5. DialogFragment 自定义弹窗

    layout文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:a ...

  6. linux笔记:linux常用命令-压缩解压命令

    压缩解压命令:gzip(压缩文件,不保留原文件.这个命令不能压缩目录) 压缩解压命令:gunzip(解压.gz的压缩文件) 压缩解压命令:tar(打包压缩目录或者解压压缩文件.打包的意思是把目录打包成 ...

  7. Java集合框架:HashMap

    转载: Java集合框架:HashMap Java集合框架概述   Java集合框架无论是在工作.学习.面试中都会经常涉及到,相信各位也并不陌生,其强大也不用多说,博主最近翻阅java集合框架的源码以 ...

  8. linux服务器挂载第二块磁盘图文解说

    文章来源:http://www.cndns.com/help/help_con.aspx?hid=394 Linux磁盘挂载是比较常见的管理操作之一.我司橙云预装的linux系统有2块盘,一块为系统盘 ...

  9. onclick="test()"与onclick="return test()"的区别

    浏览器会对页面元素的某些操作产生默认行为比如a标签跳转,form表单的提交等如果是onclick="test()"则执行该函数,然后继续自己的默认行为 <a href=&qu ...

  10. (21)odoo中的QWeb模板引擎

    -----------------更新时间18:13 2016-04-05 星期二-----------------* 概述    QWeb是odoo主要模板引擎,采用xml表述,最后生成HTML文件 ...