后缀自动机学习笔记3
来源:互联网 发布:中国人工智能会议2017 编辑:程序博客网 时间:2024/06/05 06:44
首先说一下问题描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。
输入
共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。
输出共Length(S)行,每行一个整数,表示答案。
样例输入
aab样例输出
211
状态
字符串
endpos
S
空串
{0,1,2,3,4,5,6}
1
a
{1,2,5}
2
aa
{2}
3
aab
{3}
4
aabb,abb,bb
{4}
5
b
{3,4,6}
6
aabba,abba,bba,ba
{5}
7
aabbab,abbab,bbab,bab
{6}
8
ab
{3,6}
9
aabbabd,abbabd,bbabd,babd,abd,bd,d
{7}
先构建SAM,顺便将主干点标示出来,然后对slink构成的树自底向上用拓扑排序构件出来|endpos(st)|
值得注意的是ans[1], ans[2], ... ans[length(S)]一定是一个单调递减序列。所以我们对于每个状态st,只需要更新ans[maxlen(st)]。之后令i = length(S)-1 .. 1,从后向前扫描一遍,令ans[i] = max(ans[i], ans[i+1]),即可。
代码:
//// main.cpp// hiho129//// Created by 小哲 on 16/12/17.// Copyright © 2016年 小哲. All rights reserved.//#include <iostream>#include <string.h>#include <queue>using namespace std;const int MAXL = 1000000;string s;int n = 0;int maxlen[2 * MAXL + 10], minlen[2 * MAXL + 10], trans[2 * MAXL + 10][26], slink[2 * MAXL + 10],lv[2*MAXL],ans[MAXL],endpos[2*MAXL];int du[2*MAXL];int new_state(int _maxlen, int _minlen, int* _trans, int _slink) { maxlen[n] = _maxlen; minlen[n] = _minlen; for(int i = 0; i < 26; i++) { if(_trans == NULL) trans[n][i] = -1; else trans[n][i] = _trans[i]; } slink[n] = _slink; lv[n]=0; endpos[n]=0; du[n]=0; return n++;}int add_char(char ch, int u) { int c = ch - 'a'; int z = new_state(maxlen[u] + 1, -1, NULL, -1); lv[z]=1; int v = u; while(v != -1 && trans[v][c] == -1) { trans[v][c] = z; v = slink[v]; } if(v == -1) { //最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移 minlen[z] = 1; slink[z] = 0; return z; } int x = trans[v][c]; if(maxlen[v] + 1 == maxlen[x]) { //较简单的情况,不用拆分x minlen[z] = maxlen[x] + 1; slink[z] = x; return z; } int y = new_state(maxlen[v] + 1, -1, trans[x], slink[x]); //最复杂的情况,拆分x slink[y] = slink[x]; minlen[x] = maxlen[y] + 1; slink[x] = y; minlen[z] = maxlen[y] + 1; slink[z] = y; int w = v; while(w != -1 && trans[w][c] == x) { trans[w][c] = y; w = slink[w]; } minlen[y] = maxlen[slink[y]] + 1; return z;}void getEndpos()// 拓扑排序{ for (int i=1;i<n ; i++) { du[slink[i]]++; } queue<int> qu; for (int i=1; i<n; i++) { if (!du[i]) { qu.push(i); } } while (!qu.empty()) { int v = qu.front(); // 从队列中取出一个顶点 qu.pop(); if (lv[v]) { endpos[v]++; } endpos[slink[v]]+=endpos[v]; du[slink[v]]--; if (!du[slink[v]]) { qu.push(slink[v]); } }}void getAns(){//扫描获取值 for (int i=0; i<=s.length(); i++) { ans[i]=0; } for (int i=0; i<n; i++) { ans[maxlen[i]]=max(ans[maxlen[i]], endpos[i]); } for (int i=s.length()-1; i>0; i--) { ans[i]=max(ans[i],ans[i+1]); }}int main(int argc, const char * argv[]) { int nextI=new_state(0, -1, NULL, -1);; cin>>s; for (int i=0; i<s.length(); i++) { nextI= add_char(s[i],nextI); } getEndpos(); getAns(); for (int i=1; i<=s.length(); i++) { cout<<ans[i]<<endl; } return 0;}
- 后缀自动机学习笔记3
- 后缀自动机学习笔记
- 后缀自动机学习笔记
- [Notes] 后缀自动机学习笔记
- [学习笔记] 后缀自动机学习笔记
- 后缀自动机(SAM)学习笔记
- SAM 后缀自动机——学习笔记
- 【字符串数据结构后缀系列Part2】后缀自动机学习笔记
- 后缀自动机 笔记
- 后缀自动机学习资料
- 后缀自动机学习
- 后缀自动机学习
- 后缀自动机学习
- 后缀自动机学习
- 后缀自动机学习总结
- 后缀自动机学习小记
- 后缀自动机学习资料
- 学习后缀自动机想法
- Makefile和shell脚本简单编写
- 标准BP与累计BP
- 设置adapter的item的背景时 不能使用根布局的属性
- ehcache memcache redis 三大缓存男高音
- ssh新手练手项目——员工curd操作和未登录拦截
- 后缀自动机学习笔记3
- Oracle 系统时间 以及 取记录条数
- 1 第一个网络爬虫(1)
- Android-单例Toast
- windows/linux下,把mysql数据库,sql导出表数据到excel中
- java 学习篇(一)
- android中scaleType详解
- Android之---加载图片的三种方式
- RCNN:Bounding-Box(BB)regression