HihoCoder1465 重复旋律8(后缀自动机)
描述
小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(后缀自动机)的更多相关文章
- HihoCoder1449 重复旋律6(后缀自动机)
描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对 ...
- hihoCoder.1465.后缀自动机五 重复旋律8(后缀自动机)
题目链接 \(Description\) 给定母串S,求模式串的循环同构串在S中的出现次数. \(Solution\) 将模式串s复制一遍,在母串的SAM上匹配,记录以每个位置作为后缀所能匹配的最大长 ...
- hihoCoder 1403 后缀数组一·重复旋律(后缀数组+单调队列)
#1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...
- 【HIHOCODER 1403】后缀数组一·重复旋律(后缀数组)
描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列. 小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律.旋律是一段连续的数列,相似的旋律在原数列 ...
- HihoCoder 重复旋律
あの旋律を何度も繰り返しでも.あの日見た光景を再現できない 无论将那段旋律重复多少次,也无法重现那一日我们看到的景象 もし切ないならば.時をまきもどしてみるかい? 若是感到惆怅的话,要试着让时光倒流吗 ...
- HIHOcoder1465 后缀自动机五·重复旋律8
思路 后缀自动机求最长循环串 首先有一个常用的处理技巧,将串复制一遍,长度大于n的子串中就包含了一组循环子串 然后是后缀自动机如何处理最长公共子串的问题 维护两个变量,u和l,u代表当前位置的最长公共 ...
- BZOJ 后缀自动机四·重复旋律7
后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的 ...
- hihoCoder 后缀自动机三·重复旋律6
后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...
- hihoCoder #1445 : 后缀自动机二·重复旋律5
#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...
随机推荐
- iOS URL Loading System / HTTP 重定向 认识与学习
一个朋友问了我一个问题,需求是这样的:他要用本地的H5资源 替换 链接资源, 但是判断链接资源时候 因为一些操作请求本地化了之后 一些操作比如请求服务器使用的是http开头,然而本地资源一直是以f ...
- UI控件之UIView与动画
UIView:用来展示用户的界面,响应用户的操作(继承自UIResponder) UIView的作用:绘图.动画.处理事件 UIView可以包含和管理子视图,并且决定子视图的位置大小 获取所有的子视图 ...
- 常用的机器学习&数据挖掘知识点
Basis(基础):MSE(Mean Square Error 均方误差),LMS(LeastMean Square 最小均方),LSM(Least Square Methods 最小二乘法),MLE ...
- JSP笔记01——尝试
JSP ————> servlet 我的第1个Java Web应用程序——index.jsp 我的第2个Java Web应用程序——welcome-file 我的第3个Java Web应用程序— ...
- 【Flask】Sqlalchemy 子查询
### subquery:子查询可以让多个查询变成一个查询,只要查找一次数据库,性能相对来讲更加高效一点.不用写多个sql语句就可以实现一些复杂的查询.那么在sqlalchemy中,要实现一个子查询, ...
- SOA 面向服务架构 阅读笔记(一)
Service Oriented Architecture 面向服务架构 学习笔记(一) 1.业务自由 1.1 在很多企业中,业务和IT技术是各自独立的,无法使用通用的统一语言进行管理. 1.2 ...
- 标准输出:1>,2>,1>&2,2>&1
在 shell 程式中,最常使用的 FD (file descriptor) 大概有三个, 分别是: 0 是一个文件描述符,表示标准输入(stdin)1 是一个文件描述符,表示标准输出(stdout) ...
- JavaWeb Cookie
1. Cookie 1.1. Cookie概述 Cookie译为小型文本文件或小甜饼,Web应用程序利用Cookie在客户端缓存服务器端文件.Cookie是以键值对形式存储在客户端主机硬盘中,由服务器 ...
- 单文件夹下的C程序如何编写Makefile文件
通过学习已经学会了GCC的一些基础的命令,以及如何将C语言源代码编译成可执行文件. 我们已经知道在linux环境下编译源码时,常会有以下三个步骤: ./configure make make clea ...
- 微服务(MicroServices)
微服务Architecture(MicroServices) 微服务架构简单的定义 采用一组Service的方式来构建一个应用,服务独立部署在不同的进程(Container)中,不同Service通过 ...