1465 : 后缀自动机五·重复旋律8

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

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

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

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

解题方法提示

输入

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

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

输出

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

样例输入

abac
3
a
ab
ca

样例输出

2
2
1

题目中已经有题解了,这里简略的讲一下,还是很简单的

还是先放一下这张经典的图:"aabbabd"的SAM:

先解决一个简单的问题:给你两个串S和T,求出T和S的最长公共子串(注意子串是要连续的)

当然先对串S求后缀自动机

之后对于串T的每个字符T[i],求出len[i] = 以i结尾的最长公共子串长度,u[i] = 以T[i]结尾的最长公共子串所在的SAM节点

那么如何线性求出所有的len[i] 和u[i] 呢?

很好办,初始u[0] = S,len = 0,之后对于当前字符T[k]

  1. 如果trans(u[k-1], T[k])!=NULL,则u[k] = trans(u[k-1], T[k]),len[k] = len[k-1]+1,搞定!
  2. 如果rans(u[k-1], T[k])==NULL,则u[k-1] = pre(u[k-1]),len[k-1] = longest(u[k-1]),继续执行步骤①直到满足为止或者回到后缀自动机的根节点S后仍然无法匹配

接着解决问题(2):给你两个串S和T,求出T的所有前缀分别在S中出现了多少次

只要对字符串T求出所有的u[i]和len[i],之后求出后缀自动机中每个节点的|endpos|(这个在这里有讲解)

答案就很明显了,对于当前前缀T[1..i],答案就是节点u[i]的|endpos|值

最后一个问题:给你两个串S和T,求出T的所有循环同构在S中总共出现了多少次

如果前两个问题都会做的话,这题就应该很容易有大致思路了:

设T原本长度为n,将T复制一遍拼在自身后面,之后求出T所有长度≥n的前缀T[1..i]在S中出现的次数之和就是答案

然后这样做肯定会有错误计算,所以还需要处理以下两种情况避免错误计算

  1. 前缀的长度很明显会≥n:只需沿着当前u[i]的Suffix Links不停回退,直到找到长度刚好=n的那段后缀T[i-n+1...i]所在的节点u[i]'即可
  2. 会出现完全相同的两段后缀,这个时候会重复: 这个就更好办了,标记一下所有的u[i],每个u[i]对答案的贡献显然不可能超过1次
#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct Node
{int len, pre;int Next[26];
}Node;
Node tre[500005];
vector<int> G[500005];
int cnt, last, siz[500005], ans[500005], vis[500005];
char str[200005];
void Init()
{cnt = last = 0;memset(tre, 0, sizeof(tre));tre[cnt++].pre = -1;
}
void Insert(char ch)
{int p, q, now, rev;p = last, now = cnt++;tre[now].len = tre[last].len+1;siz[now]++;while(p!=-1 && tre[p].Next[ch-'a']==0){tre[p].Next[ch-'a'] = now;p = tre[p].pre;}if(p==-1)tre[now].pre = 0;else{q = tre[p].Next[ch-'a'];if(tre[q].len==tre[p].len+1)tre[now].pre = q;else{rev = cnt++;tre[rev] = tre[q];tre[rev].len = tre[p].len+1;tre[q].pre = tre[now].pre = rev;while(p!=-1 && tre[p].Next[ch-'a']==q){tre[p].Next[ch-'a'] = rev;p = tre[p].pre;}}}last = now;
}
void SechSL(int u)
{int i, v;for(i=0;i<G[u].size();i++){v = G[u][i];SechSL(v);siz[u] += siz[v];}ans[tre[u].len] = max(ans[tre[u].len], siz[u]);
}
int main(void)
{char ch;int n, i, Q, len, now, ans;scanf("%s%d", str+1, &Q);n = strlen(str+1);Init();for(i=1;i<=n;i++)Insert(str[i]);for(i=1;i<=cnt-1;i++)G[tre[i].pre].push_back(i);SechSL(0);while(Q--){scanf("%s", str+1);n = strlen(str+1);for(i=1;i<=n-1;i++)str[i+n] = str[i];ans = now = len = 0;for(i=1;i<=n*2-1;i++){ch = str[i]-'a';while(now && tre[now].Next[ch]==0)now = tre[now].pre, len = tre[now].len;if(tre[now].Next[ch])now = tre[now].Next[ch], len++;if(len>=n){while(len>=n && tre[tre[now].pre].len>=n)now = tre[now].pre, len  = tre[now].len;}if(len>=n && vis[now]!=Q+1000)vis[now] = Q+1000, ans += siz[now];}printf("%d\n", ans);}return 0;
}

hihocoder 1465 : 后缀自动机五·重复旋律8(后缀自动机+最长公共子串)相关推荐

  1. HihoCoder - 1465 后缀自动机五·重复旋律8(后缀自动机)

    题目链接:点击查看 题目大意:给出一个模式串,在给出多个匹配串,问每个匹配串与其"循环相似旋律"的字符串,在模式串中出现的总次数,"循环相似旋律"指的是一个字符 ...

  2. HihoCoder - 1445 后缀自动机二·重复旋律5(后缀自动机)

    题目链接:点击查看 题目大意:给出一个字符串 s ,求 s 中本质不同的子串的数量 题目分析:因为 s 的长度给到了 1e6 ,用后缀数组可能会超时,所以最好的方法肯定是用后缀自动机来做,因为每个节点 ...

  3. hihocoder #1465 : 后缀自动机五·重复旋律8

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi发现旋律可以循环,每次把一 ...

  4. HihoCoder - 1457 后缀自动机四·重复旋律7(后缀自动机)

    题目链接:点击查看 题目大意:给出 n 个由 0~9 的数字组成的字符串,现在要求每个子串所表示的十进制下数字的累加之和 题目分析:因为对于字符串的所有子串而言数量无疑是非常庞大的,所以我们选择用后缀 ...

  5. #1407 : 后缀数组二·重复旋律2 (不可重叠最长重复子串问题)

    题目链接 思路 求不可重叠最长重复子串,也可以利用height[i]height[i]height[i]. 二分枚举答案KKK 当height[i]≥Kheight[i] \ge Kheight[i] ...

  6. hihocoder 1457 : 后缀自动机四·重复旋律7(后缀自动机+拓扑序BFS)

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

  7. hihocoder 1449 : 后缀自动机三·重复旋律6(后缀自动机)

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

  8. hiho一下第128周 后缀自动机二·重复旋律5

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

  9. hiho一下120周 后缀数组一·重复旋律

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

最新文章

  1. linux md5sum 的用法(转)
  2. J.U.C系列(六)ForkJoin的使用
  3. ubuntu14.04环境下spyder的安装
  4. 在阿里,我们如何管理代码分支?
  5. 如何查看电脑CPU实时功耗
  6. php读取oracle,php读取oracle中数据库文件
  7. Windows IOCP模型与Linux EPOLL模块之比较-
  8. java 1.6 jre 下载_jre1.6下载-Java环境 官方版 - 安下载
  9. 《C++ Primer 第5版》-13.3交换操作-康奈尔笔记
  10. android高仿ios键盘,iOS仿工商银行app自定义键盘
  11. 使用假设检验分析PS4,XBox,Switch 谁是最好的游戏主机
  12. CSDN英雄会上会英雄
  13. 用户输入查询与拼音首字母的结合,提高用户的操作体验
  14. Java基础 DAY11
  15. 数字图像处理 --- 图像的傅里叶变换的频谱特征 二(方向性)
  16. 【open3d】显示kitti 点云数据和bbox
  17. Arduino基础入门篇17—四位数码管的驱动
  18. 【Arduino】2017年电子设计大赛B题 滚球控制系统|板球系统
  19. 小达人点读笔报电量低无法充电故障的处理
  20. 水桶服务器eula文件,craftbukkit

热门文章

  1. python利器-bluepy 一款python封装的BLE利器简单介绍
  2. python工资这么高为什么不学-为什么我不建议你学Python?
  3. python能做什么程序-学完python可以做什么?
  4. python练手经典100例-Python练手项目实例汇总(附源码下载)
  5. 灵云语音识别(ASR)实现实时识别
  6. 素数表的获取 O(nloglogn)复杂
  7. python强转字符串_在Python 3中将Exception转换为字符串
  8. echarts环形图
  9. ffmpeg源码分析:transcode()函数
  10. 手机怎么打开f12_碰到生僻字看不懂怎么办?打开手机这个开关,一键即可秒懂...