POJ1743 Musical Theme (后缀数组 & 后缀自动机)最大不重叠相似子串
A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of musical timing; but, this programming task is about notes and not timings.
Many composers structure their music around a repeating &qout;theme&qout;, which, being a subsequence of an entire melody, is a sequence of integers in our representation. A subsequence of a melody is a theme if it:
- is at least five notes long
- appears (potentially transposed -- see below) again somewhere else in the piece of music
- is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s)
Transposed means that a constant positive or negative value is added to every note value in the theme subsequence.
Given a melody, compute the length (number of notes) of the longest theme.
One second time limit for this problem's solutions!
Input
The last test case is followed by one zero.
Output
Sample Input
30
25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
82 78 74 70 66 67 64 60 65 80
0
Sample Output
5
Hint
题解:最大不重叠相似子串。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=;
int n,s[maxn];
int rk[maxn],sa[maxn],height[maxn];
int x[maxn<<],y[maxn<<],c[maxn]; inline void get_SA(int m)
{
for(int i=;i<=m;++i) c[i]=;
for(int i=;i<=n;++i) ++c[x[i]=s[i]];
for(int i=;i<=m;++i) c[i]+=c[i-];
for(int i=n;i>=;--i) sa[c[x[i]]--]=i;
for(int k=;k<=n;k<<=)
{
int num=;
for(int i=n-k+;i<=n;++i) y[++num]=i;
for(int i=;i<=n;++i) if(sa[i]>k) y[++num]=sa[i]-k;
for(int i=;i<=m;++i) c[i]=;
for(int i=;i<=n;++i) ++c[x[i]];
for(int i=;i<=m;++i) c[i]+=c[i-];
for(int i=n;i>=;--i) sa[c[x[y[i]]]--]=y[i],y[i]=;
swap(x,y);
x[sa[]]=;
num=;
for(int i=;i<=n;++i)
x[sa[i]]=(y[sa[i]]==y[sa[i-]]&&y[sa[i]+k]==y[sa[i-]+k])?num:++num;
if(num==n) break;
m=num;
}
}
inline void get_height()
{
int k=;
for(int i=;i<=n;++i) rk[sa[i]]=i;
for(int i=;i<=n;++i)
{
if(rk[i]==) continue;
if(k) --k;
int j=sa[rk[i]-];
while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;
}
}
bool check(int k)
{
int mx=-INF,mi=INF;
for(int i=;i<=n;++i)
{
if(height[i]>=k)
{
mx=max(mx,max(sa[i],sa[i-]));
mi=min(mi,min(sa[i],sa[i-]));
if(mx-mi>k) return true;
}
else mx=-INF,mi=INF;
}
return false;
} int main()
{
while(scanf("%d",&n) && n)
{
int pre,now; n--;
scanf("%d",&pre);
for(int i=;i<=n;++i) scanf("%d",&now),s[i]=now-pre+,pre=now;
get_SA();
get_height(); int l=,r=n>>;
while(l+<r)
{
int mid=l+r>>;
if(check(mid)) l=mid;
else r=mid;
}
int ans;
if(check(r)) ans=r;
else ans=l;
printf("%d\n",ans>=? ans+:);
} return ;
}
后缀自动机
/********* 后缀自动机做法 ***********/
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define inf 1000000000
#define mod 1000000007
#define pa pair<int,int>
#define ll long long
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,a[];
struct sam{
int last,cnt,ans;
int l[],r[],mx[],fa[],a[][];
int q[],v[];
void init()
{
memset(l,,sizeof(l));
memset(r,,sizeof(r));
memset(v,,sizeof(v));
memset(mx,,sizeof(mx));
memset(fa,,sizeof(fa));
memset(a,,sizeof(a));
last=cnt=;ans=;
}
void extend(int c)
{
int p=last,np=last=++cnt;mx[np]=mx[p]+;
l[np]=r[np]=mx[np];
while(!a[p][c]&&p)a[p][c]=np,p=fa[p];
if(!p)fa[np]=;
else
{
int q=a[p][c];
if(mx[p]+==mx[q]) fa[np]=q;
else
{
int nq=++cnt;mx[nq]=mx[p]+;
memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
while(a[p][c]==q) a[p][c]=nq,p=fa[p];
}
}
}
void solve()
{
for(int i=;i<=cnt;i++) v[mx[i]]++;
for(int i=;i<=n;i++) v[i]+=v[i-];
for(int i=cnt;i;i--) q[v[mx[i]]--]=i;
for(int i=cnt;i;i--)
{
int p=q[i];
l[fa[p]]=min(l[fa[p]],l[p]);
r[fa[p]]=max(r[fa[p]],r[p]);
}
for(int i=;i<=cnt;i++)
ans=max(ans,min(mx[i],r[i]-l[i]));
if(ans<)puts("");
else printf("%d\n",ans+);
}
} sam;
int main()
{
while(scanf("%d",&n))
{
if(n==)break;
for(int i=;i<=n;i++) a[i]=read();n--;
for(int i=;i<=n;i++) a[i]=a[i+]-a[i]+;
sam.init();
for(int i=;i<=n;i++)
sam.extend(a[i]);
sam.solve();
}
return ;
}
POJ1743 Musical Theme (后缀数组 & 后缀自动机)最大不重叠相似子串的更多相关文章
- POJ1743 Musical Theme(二分+后缀数组)
题目大概是给n个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等. 这题是传说中楼教主男人八题之一,虽然已经是用后缀数组解决不可重叠最 ...
- poj 1743 后缀数组 求最长不重叠重复子串
题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题. “主题”是整个音符序列的一个子串,它需要满足如下条件:1 ...
- Musical Theme - poj 1743(求最大不重叠重复子串)
题目大意: * 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题. * “主题”是整个音符序列的一个子串,它需要满 ...
- POJ1743 Musical Theme —— 后缀数组 重复出现且不重叠的最长子串
题目链接:https://vjudge.net/problem/POJ-1743 Musical Theme Time Limit: 1000MS Memory Limit: 30000K Tot ...
- 字符串的模板 Manacher kmp ac自动机 后缀数组 后缀自动机
为何scanf("%s", str)不需要&运算 经常忘掉的字符串知识点,最好不加&,不加&最标准,指针如果像scanf里一样加&是错的,大概是未定 ...
- 【整理】如何选取后缀数组&&后缀自动机
后缀家族已知成员 后缀树 后缀数组 后缀自动机 后缀仙人掌 后缀预言 后缀Splay ? 后缀树是后缀数 ...
- loj6173 Samjia和矩阵(后缀数组/后缀自动机)
题目: https://loj.ac/problem/6173 分析: 考虑枚举宽度w,然后把宽度压位集中,将它们哈希 (这是w=2的时候) 然后可以写一下string=“ac#bc” 然后就是求这个 ...
- 利用后缀数组(suffix array)求最长公共子串(longest common substring)
摘要:本文讨论了最长公共子串的的相关算法的时间复杂度,然后在后缀数组的基础上提出了一个时间复杂度为o(n^2*logn),空间复杂度为o(n)的算法.该算法虽然不及动态规划和后缀树算法的复杂度低,但其 ...
- poj 3693 后缀数组 重复次数最多的连续重复子串
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8669 Acc ...
- 笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)
议题:后缀数组(Suffix Array) 分析: 后缀树和后缀数组都是处理字符串的有效工具,前者较为常见,但后者更容易编程实现,空间耗用更少:后缀数组可用于解决最长公共子串问题,多模式匹配问题,最长 ...
随机推荐
- Scss的使用场景
一.Scss 1.CSS有几个缺点 语法不够强大,没有变量和合理的样式复用机制 使得逻辑上相关的属性值必须以字面的形式重复输出,难以维护 动态的样式语言为css富裕了动态语言的特性 极大的提高了样式语 ...
- docker——数据卷volume:文件共享
volume——如何让容器中的一个目录与宿主机的一个目录进行绑定,实现容器与宿主机之间的文件共享? 数据卷volume功能特性 数据卷:是一个可供一个或多个容器使用的特殊目录,实现让容器中的一个目录和 ...
- [JQuery] JQuery学习笔记
1.2019年10月20日14:43:48 学习HOW2J. 2.JQuery是一个javascript的框架,是对javascript的一种封装, 通过JQuery可以非常方便的操作html的元素 ...
- PHP 向数组头部插入数据
PHP 向数组头部插入数据 函数: array_unshift() 示例: $s = array('a' => 0, 'b' => 3); array_unshift($s, '5'); ...
- python:collections模块
Counter类 介绍:A counter tool is provided to support convenient and rapid tallies 构造:class collections. ...
- MAC系统下,Jmeter5.1.1 无法录制问题
问题一: 点击[start]先出现一个检查证书信息的弹窗,确保删除旧的安装新的,并且需要信任证书 (一般证书只需要信任一下即可,每次启动都会有这个弹窗提醒) 问题二: MAC OS系统使用Jmeter ...
- vue引用组件的两个方法
<template> <div> <myComponent></myComponent> </div> </template> ...
- 小白学 Python 爬虫(4):前置准备(三)Docker基础入门
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- Java学习笔记 线程池使用及详解
有点笨,参考了好几篇大佬们写的文章才整理出来的笔记.... 字面意思上解释,线程池就是装有线程的池,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程 ...
- (四十五)golang--反射
反射基本介绍: (1)反射可以在运行时动态获取变量的各种信息,比如变量的类型.类别: (2)如果是结构体变量,还可以获取结构体本身的信息(包括结构体字段.方法): (3)通过反射,可以修改变量的值,可 ...