poj1743 Musical Theme(后缀数组|后缀自动机)
2015-11-27
【思路】
1) 据题意处理字符串
2) 后缀数组。二分长度k,问题成为了判定是否存在两个及以上长度不小于k且互不重叠的子串。根据height数组划分后缀,满足两个条件:一是一组内height值不小于k(保证组内任两个长度不小于k即存在长度不小于k的子串),二是组内后缀sa值的最大最小值之差大于等于k(保证两个子串不重叠)。
需要注意n==1时需要特判。
1/为什么可以划分height数组呢?首先height[i]代表lcp(suffix(sa[i]),suffix(sa[i-1])),所以height所对应的后缀是有序的,如果划分出现height<k的话以后的后缀与改组内的lcp一定不大于k-1,所以不会出现后面的再划分到改组的情况。
【代码】
#include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; const int maxn = +; int s[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn],n; void build_sa(int m) {
int i,*x=t,*y=t2;
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 p=;
for(int i=n-k;i<n;i++) y[p++]=i;
for(int i=;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=;i<m;i++) c[i]=;
for(int i=;i<n;i++) c[x[y[i]]]++;
for(int i=;i<m;i++) c[i]+=c[i-];
for(int i=n-;i>=;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y);
p=; x[sa[]]=;
for(int i=;i<n;i++)
x[sa[i]]=y[sa[i-]]==y[sa[i]] && y[sa[i-]+k]==y[sa[i]+k]?p-:p++;
if(p>=n) break;
m=p;
}
} int rank[maxn],height[maxn];
void getHeight() {
int i,j,k=;
for(int i=;i<n;i++) rank[sa[i]]=i;
for(int i=;i<n;i++) {
if(k) k--;
int j=sa[rank[i]-];
while(s[i+k]==s[j+k]) k++;
height[rank[i]]=k;
}
} bool can(int k) {
int min=sa[],max=sa[];
for(int i=;i<n;i++) {
if(height[i]<k) min=max=sa[i];
if(sa[i]<min) min=sa[i];
if(sa[i]>max) max=sa[i];
if(max-min>=k) return true;
}
return false;
} int main() {
while(scanf("%d",&n)== && n)
{
for(int i=;i<n;i++)scanf("%d",&s[i]);
for(int i=n-;i>;i--)s[i]=s[i]-s[i-]+;
n--;
for(int i=;i<n;i++)s[i]=s[i+];
s[n]=;
build_sa();
getHeight();
int L=,R=n/;
while(L<R) {
int M=L+(R-L+)/;
if(can(M)) L=M; else R=M-;
}
L++;
if(L<=) printf("0\n");
else printf("%d\n",L);
}
return ;
}
2016-2-19
【思路】
SAM+DP
处理出right集的最大值mx和最小值mn,即该状态对应所有字符串的结束位置的最大与最小,递推式为:
mx[p]=max{ l[p], mx[np],np->fa=p }
mn[p]=min{ l[p], mn[np],np->fa=p }
则状态i对应字符串中的最长重复子串的长度为min{l[i],mx[i]-mn[i]},可以拿个栗子自己看一下,这样保证了不重叠。然后取所有状态的最大值即可。
【代码】
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int N = *1e4+;
const int sigma = ; int s[N/];
int root,last,sz,ch[N][sigma],fa[N],l[N],mn[N],mx[N];
int b[N],cnt[N],n; void init() {
sz=; root=last=++sz;
memset(fa,,sizeof(fa));
memset(mx,,sizeof(mx));
memset(mn,,sizeof(mn));
memset(cnt,,sizeof(cnt));
memset(ch,,sizeof(ch));
}
void add(int x) {
int c=s[x];
int p=last,np=++sz; last=np;
mn[np]=mx[np]=l[np]=x;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=root;
else {
int q=ch[p][c];
if(l[p]+==l[q]) fa[np]=q;
else {
int nq=++sz; l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
for(;p&&q==ch[p][c];p=fa[p]) ch[p][c]=nq;
}
}
}
void solve() {
for(int i=;i<=sz;i++) cnt[l[i]]++;
for(int i=;i<=n;i++) cnt[i]+=cnt[i-];
for(int i=;i<=sz;i++) b[cnt[l[i]]--]=i;
int ans=;
for(int i=sz;i;i--) {
int p=b[i];
if(fa[p]) {
if(mn[fa[p]]>mn[p]) mn[fa[p]]=mn[p];
if(mx[fa[p]]<mx[p]) mx[fa[p]]=mx[p];
}
}
for(int i=;i<=sz;i++)
ans=max(ans,min(l[i],mx[i]-mn[i]));
if(ans<) puts("");
else printf("%d\n",ans+);
}
void read(int& x) {
char c=getchar(); int f=; x=;
while(!isdigit(c)){if(c=='-')f=-;c=getchar();}
while(isdigit(c)) x=x*+c-'',c=getchar();
x*=f;
} int main() {
while(read(n),n) {
init();
for(int i=;i<=n;i++) read(s[i]); n--;
for(int i=;i<=n;i++) s[i]=s[i+]-s[i]+,add(i);
solve();
}
return ;
}
poj1743 Musical Theme(后缀数组|后缀自动机)的更多相关文章
- POJ1743 Musical Theme(二分+后缀数组)
题目大概是给n个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等. 这题是传说中楼教主男人八题之一,虽然已经是用后缀数组解决不可重叠最 ...
- 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” 然后就是求这个 ...
- POJ1743 Musical Theme (后缀数组 & 后缀自动机)最大不重叠相似子串
A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the ...
- POJ1743 Musical Theme [后缀数组]
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 27539 Accepted: 9290 De ...
- POJ1743 Musical Theme [后缀数组+分组/并查集]
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 27539 Accepted: 9290 De ...
- POJ-1743 Musical Theme,后缀数组+二分!
Musical Theme 人生第一道后缀数组的题,采用大众化思想姿势极其猥琐. 题意:给你n个 ...
随机推荐
- mvc4+jquerymobile页面加载时无法绑定事件
问题:在view里写js,在页面第一次加载完成后,无法触发事件, 如:按钮click事件,已经在$(function(){ 添加了click });但就是无法触发,必须刷新下才可以. 原因分析: 主 ...
- 自定义Window 服务
自定义window 服务 开发到使用的流程: 1.完成对应的代码之后(代码在底下),右键MyService.cs 添加安装程序 2.添加window服务安装程序打开Service1.cs[设计]页面, ...
- E/Trace: error opening trace file: No such file or directory
E/Trace: error opening trace file: No such file or directory (2) 有这一个错误,想了一下,然后发现是 AdroidManifest.xm ...
- servlet 项目 ,,启动没问题,,但是,一请求也面就报错误。。。。求解决。。。。。。。。。。。。。各种百度,都没解决了啊。。。。。急急急急急急急急急急急急急急急急急急
信息: Server startup in 1674 mslog4j:WARN No appenders could be found for logger (com.mchange.v2.log.M ...
- Xcode断点的一些黑魔法
转自 只会左键断点?是时候试试这样那样断点了 编码不能没调试,调试不能没断点(Break Point).XCode的断点功能也是越来越强大. 基本断点 如下图,这种是最常用的断点,也是最容易设置.左键 ...
- 极端气候频现 五款开发天气预报应用的API
http://www.csdn.net/article/2014-02-07/2818322-weather-forecast-api-for-developing-apps
- 【HDU4348】【主席树】To the moon
Problem Description BackgroundTo The Moon is a independent game released in November 2011, it is a r ...
- javascript-处理XML
/** * Created by Administrator on 2015/4/4. */ var XmlUtil=(function () { var createDocument= functi ...
- JS判断终端(Android IOS)
function getMobileOperatingSystem() { var userAgent = navigator.userAgent || navigator.vendor || win ...
- arm Linux 系统调用过程
系统调用是操作系统提供给用户(应用程序)的一组接口,每个系统调用都有一个对应的系统调用函数来完成相应的工作.用户通过这个接口向操作系统申请服务,如访问硬件,管理进程等等.但是因为用户程序运行在用户空间 ...