描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。

小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”。

小Hi对此产生了浓厚的兴趣,他有若干段旋律,和一部音乐作品。对于每一段旋律,他想知道有多少在音乐作品中的子串(重复便多次计)和该旋律是“循环相似旋律”。

输入

第一行,一个由小写字母构成的字符串S,表示一部音乐作品。字符串S长度不超过100000。

第二行,一个整数N,表示有N段旋律。接下来N行,每行包含一个由小写字母构成的字符串str,表示一段旋律。所有旋律的长度和不超过 100000。

输出

输出共N行,每行一个整数,表示答案。

样例输入
abac
3
a
ab
ca
样例输出
2
2
1
 【技巧】:

现在我们要处理T的循环同构串们。这里有一个常用的技巧,假设T的长度是n,我们令T'=T + T[1..n-1]形成一个新的串T'。例如对于"abcd",我们把"abc"拼在"abcd"后面,得到新的T="abcdabc"。这样"abcd"的循环同构串就变成了T'="abcdabc"的长度为n的子串。

小Ho:哦!然后我们再用之前讲的方法求出在每个位置T'[i]结束的最长公共子串。我们可以求出对应的(u, l),如果这时l>=n,那我们就得到了一个公共子串T'[i-l+1 .. i]。这个子串在S中出现的次数是|endpos(u)|,又恰好包含T的循环同构串T'[i-n+1 .. i]。

小Hi:基本思路是对的。但是要注意处理两个特殊情况。第一个情况是T的n个循环同构子串有重复(相同)的情况。比如T="aa",T'="aaa",还是以S="aabbabd"为例

S:  aabbabd
T': aaa
1: a (u, l) = (1, 1)
2: aa (u, l) = (2, 2), l>=n
3: aa (u, l) = (2, 2), l>=n

小Hi:T'[2]和T'[3]结尾的最长公共子串都是"aa",(u, l)都是(2, 2)。我们要避免"aa"的出现次数被统计2次,小Ho你想想要怎么办?

小Ho:恩,我们要记录一个状态是不是之前在l>=n的情况下到达过。如果到达过的话,下一次再到达就不要统计了。

小Hi:很好。我们还有第二个特殊情况要处理。那就是要区分串T'[i-l+1 .. i]出现次数和T'[i-n+1 .. i]的出现次数。前面说到,我们处理T'[i]的时候求出当前状态u和匹配长度l。这时串T'[i-l+1 .. i]一定是属于状态u的,T'[i-l+1 .. i]的出现次数是|endpos(u)|。但是这时可能l>n,所以T'[i-n+1 .. i]不一定属于状态u。T'[i-n+1 .. i]是T'[i-l+1 .. i]长度为n的后缀,可能在suffix-path(u->S)上,出现次数比T'[i-n+1 .. i]多。

小Ho:这个也好办,我们只要沿着suffix-path(u->S)向上找,找到最靠近S的v满足maxlen[v]>=n (也就是minlen[v]<=n<=maxlen[v]),统计|endpos(v)|即可。

小Hi:这里有一个关键点,我们找到v之后可以直接令u=v。以免每次向前找v的复杂度过高。

此题感悟:把trans当成KMP的fail函数,从而后缀自动机可以实现KMP和ac自动机的大部分功能。

注意题中的S=1;

此外字符串处理后再用strlen会出错?好像是。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
const int N=1e6+;
int q[N*],tail,head;
int tot,slink[*N],trans[*N][],minlen[*N],maxlen[*N],edpts[*N];
int blue[*N],ind[*N],used[*N];
char str[*N];
int newstate(int _maxlen,int _minlen,int* _trans,int _slink) {
maxlen[++tot]=_maxlen;
minlen[tot]=_minlen;
slink[tot]=_slink;
if(_trans)
for(int i=; i<; i++)
trans[tot][i]=_trans[i];
return tot;
}
int add_char(char ch,int u) {
int c=ch-'a',v=u;
int z=newstate(maxlen[u]+,-,NULL,);
blue[z]=;//绿色
while(v&&!trans[v][c]) {
trans[v][c]=z;
v=slink[v];
}
if(!v) {
minlen[z]=;
slink[z]=;
ind[]++;
return z;
}
int x=trans[v][c];
if(maxlen[v]+==maxlen[x]) {
slink[z]=x;
minlen[z]=maxlen[x]+;
ind[x]++;
return z;
}
int y=newstate(maxlen[v]+,-,trans[x],slink[x]);
slink[z]=slink[x]=y;
ind[y]+=;
minlen[x]=minlen[z]=maxlen[y]+;
while(v&&trans[v][c]==x) {
trans[v][c]=y;
v=slink[v];
}
minlen[y]=maxlen[slink[y]]+;
return z;
}
void top_sort() {
head=tail=;
for(int i=;i<=tot;i++)if(!ind[i]) q[++tail]=i;
while(head<tail) {
int u=q[++head];
if(blue[u]) edpts[u]++;
edpts[slink[u]] += edpts[u];
if(!--ind[slink[u]]) q[++tail]=slink[u];
}
}
void _count()
{
char c[*N];
scanf("%s",c);
int len,L0,i,u=,ans=,L=;//
L0=strlen(c);
for(i=;i<L0-;i++) c[i+L0]=c[i];
len=*L0-;//改成strlen就错了!!!
for(i=;i<=tot;i++) used[i]=;
for(i=;i<len;i++){
while(u!=&&trans[u][c[i]-'a']==) {
u=slink[u];
L=maxlen[u];
}
if(trans[u][c[i]-'a']>) {
u=trans[u][c[i]-'a'];
L++;
}
else {
u=;
L=;
}//
if(L>L0){
while(maxlen[slink[u]]>=L0){
u=slink[u];
L=maxlen[u];
}
}
if(L>=L0&&!used[u]) {
ans+=edpts[u];
used[u]=;
}
}
printf("%d\n",ans);
}
int main() {
scanf("%s",str);
int len=strlen(str),pre=;
tot=;
for(int i=; i<len; i++) {
pre=add_char(str[i],pre);
}
top_sort();
int T;
scanf("%d",&T);
while(T--) _count();
return ;
}

HihoCoder1465 重复旋律8(后缀自动机)的更多相关文章

  1. HihoCoder1449 重复旋律6(后缀自动机)

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对 ...

  2. hihoCoder.1465.后缀自动机五 重复旋律8(后缀自动机)

    题目链接 \(Description\) 给定母串S,求模式串的循环同构串在S中的出现次数. \(Solution\) 将模式串s复制一遍,在母串的SAM上匹配,记录以每个位置作为后缀所能匹配的最大长 ...

  3. hihoCoder 1403 后缀数组一·重复旋律(后缀数组+单调队列)

    #1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...

  4. 【HIHOCODER 1403】后缀数组一·重复旋律(后缀数组)

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列. 小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律.旋律是一段连续的数列,相似的旋律在原数列 ...

  5. HihoCoder 重复旋律

    あの旋律を何度も繰り返しでも.あの日見た光景を再現できない 无论将那段旋律重复多少次,也无法重现那一日我们看到的景象 もし切ないならば.時をまきもどしてみるかい? 若是感到惆怅的话,要试着让时光倒流吗 ...

  6. HIHOcoder1465 后缀自动机五·重复旋律8

    思路 后缀自动机求最长循环串 首先有一个常用的处理技巧,将串复制一遍,长度大于n的子串中就包含了一组循环子串 然后是后缀自动机如何处理最长公共子串的问题 维护两个变量,u和l,u代表当前位置的最长公共 ...

  7. BZOJ 后缀自动机四·重复旋律7

    后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的 ...

  8. hihoCoder 后缀自动机三·重复旋律6

    后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...

  9. hihoCoder #1445 : 后缀自动机二·重复旋律5

    #1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...

随机推荐

  1. Python3 进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  2. iOS 52个技巧学习心得笔记 第一章 熟悉OC

    1 .简单了解OC2 .在类的头文件中尽量少引入其他头文件3 .多用字面量语法 少用与之等价的方法 4 .多用类型常量 少用 #define 预处理指令5 .用枚举表示状态,选项,状态码 .简单了解O ...

  3. 主攻ASP.NET MVC4.0之重生:Jquery Mobile 列表

    代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title ...

  4. python编程常见小技巧

    #主要是记录常见的小问题以及解决办法 ##1.复制的代码,经常出现TAB和空格不一致的情况 将tab或者空格删除,然后重新打出空格或者tab就可以了: ##2.python读取文件,经常出现的编码en ...

  5. 分布式任务调度平台XXL-Job集群版搭建

    如果集群: 保存后: 启动两个 job 第二个job的配置: # web port server.port=8082 # log config logging.config=classpath:log ...

  6. 设置本地wamp环境挂载多站点同时运行

    之前写过一篇关于在Linux环境下配置虚拟主机的文章:现在又有一种场景:在本地同时写多个项目:可本地的wamp环境下默认只有一个www目录:这样经常修改目录很痛苦:那么幸福就这么猝不及防的来了:下面就 ...

  7. win7下users用户文件转移到其他盘符

    在安装完的系统中, 1.重启按F8键到修复系统界面: 2.下一步->下一步->运行dos窗口,打开dos窗口: 3.拷贝命令:robocopy "C:\Users" & ...

  8. PAT1022. Digital Library (30)

    两个坑. 一个是一直用的malloc不行了.因为malloc分配的是固定大小,之前做的题没遇到过是因为一般string都不长(malloc分配string为24个Byte),这次直接报段错误,呢们了半 ...

  9. Ubuntu linux背景指南:在开始之前需要知道哪些东西

    1.摘要 Ubuntu是一个新的GNU/Linux衍生操作系统,其目标是更多地以用户为本以及桌面应用. 因此,Ubuntu的目的是消除安装的困难,在很大程度上靠自动配置和自动探测硬件解决 问题,无须用 ...

  10. Spring Boot 注释

    1.@RestController@RestController ≍ @Controller + @ResponseBody在Controller文件 public class xxxx 前面加用于返 ...