题目大意:

给定一个字符串,接下来再给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. Android ViewPager刷新解析

    ViewPager刷新解析 原本以为PagerAdapter类似于BaseAdapter 但是使用起来发现刷新还是有区别的 解析如下 先上Demo PagerAdapter的四大函数 getCount ...

  2. go框架

    beego 的 http server… Author 逆雪寒 2015.12.02 原文地址 https://github.com/nixuehan/beego_you_know/blob/mast ...

  3. Oracle SQL 调优之 sqlhc

    SQL 执行慢,如何 快速准确的优化. sqlhc 就是其中最好工具之一 通过获得sql所有的执行计划,列出实际的性能的瓶颈点,列出 sql 所在的表上的行数,每一列的数据和分布,现有的索引,sql ...

  4. Libsvm:脚本(subset.py、grid.py、checkdata.py) | MATLAB/OCTAVE interface | Python interface

    1.脚本 This directory includes some useful codes: 1. subset selection tools. (子集抽取工具) subset.py 2. par ...

  5. Eclipse全面提速小技巧

    转自:http://rongmayisheng.com/post/eclipse%E5%85%A8%E9%9D%A2%E6%8F%90%E9%80%9F 欢迎关注我的社交账号: 博客园地址: http ...

  6. 日期操作类--GregorianCalendar类

    GregorianCalendar--API JavaTM Platform Standard Ed. 6 GregorianCalendar类 Calendar类实现了公历日历,GregorianC ...

  7. ubuntu12.04 安装配置jdk1.7

    第一步:下载jdk-7-linux-i586.tar.gz wget -c http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-i586 ...

  8. nginx配置 php 单入口

    location / {            root   html;            index  index.html index.htm index.php; if (!-e $requ ...

  9. JAVA_安装JDK和Eclipse

    大二开始前,找的是学长帮忙直接安装的,这个寒假抽空体验重装系统,同时,体验安装JDK和Eclipse.O(∩_∩)O 1.jdk 1)官方网址(下载JDK)   http://www.oracle.c ...

  10. 去除DataTable重复数据的三种方法

    业务需求 最近做一个把源数据库的数据批次导出到目标数据库.源数据库是采集程序采集而来的原始数据库,所以需要对其进行一些处理(过滤一些为空,长度太短或太长,非法字符,重复数据)然后在进行入库. 其中要避 ...