博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj1396】 识别子串
阅读量:5111 次
发布时间:2019-06-13

本文共 2744 字,大约阅读时间需要 9 分钟。

 (题目链接)

题意

  问字符串S每一位的最短识别子串是多长(识别子串指包含这个字符且只出现在S中一次的子串)。

Solution

  很简单,搞出后缀数组以后,对于每一个后缀i,都可以求出从i向后延伸的最短识别子串,也就是${max(height[rank[i]],height[rank[i]+1])+1}$,注意一种情况,就是i与排在它相邻位置的后缀的lcp就等于它自己的长度,这种情况i是没有向后延伸的识别子串的。

  所以正着求一遍后缀数组,反着求一遍后缀数组,然后线段树区间修改每个后缀的最短识别子串覆盖范围内的点就可以了。

细节

  太久没写线段树,都忘记要开4倍空间了→_→

代码

// bzoj1396#include
#include
#include
#include
#include
#include
#include
#define LL long long#define inf 2147483640#define Pi acos(-1.0)#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);using namespace std;const int maxn=100010;struct Segtree {int l,r,s,tag;}tr[maxn<<2];int sa[maxn],height[maxn],rank[maxn];char s[maxn];namespace Suffix { int wa[maxn],wb[maxn],ww[maxn]; bool cmp(int *r,int a,int b,int l) { return r[a]==r[b] && r[a+l]==r[b+l]; } void da(char *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb; for (i=0;i<=m;i++) ww[i]=0; for (i=1;i<=n;i++) ww[x[i]=r[i]]++; for (i=1;i<=m;i++) ww[i]+=ww[i-1]; for (i=n;i>=1;i--) sa[ww[x[i]]--]=i; for (p=0,j=1;p
j) y[++p]=sa[i]-j; for (i=0;i<=m;i++) ww[i]=0; for (i=1;i<=n;i++) ww[x[y[i]]]++; for (i=1;i<=m;i++) ww[i]+=ww[i-1]; for (i=n;i>=1;i--) sa[ww[x[y[i]]]--]=y[i]; for (swap(x,y),p=x[sa[1]]=1,i=2;i<=n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p : ++p; } } void calheight(char *r,int *sa,int n) { for (int i=1;i<=n;i++) rank[sa[i]]=i; for (int k=0,i=1;i<=n;i++) { if (k) k--; int j=sa[rank[i]-1]; while (r[i+k]==r[j+k]) k++; height[rank[i]]=k; } }}namespace SegTree { void build(int k,int s,int t) { tr[k].l=s,tr[k].r=t; if (s==t) {tr[k].s=inf;return;} int mid=(s+t)>>1; if (s<=mid) build(k<<1,s,mid); if (mid
>1; if (l==s && r==t) {if (tr[k].s>val) tr[k].s=tr[k].tag=val;return;} if (tr[k].tag) pushdown(k); if (t<=mid) update(k<<1,s,t,val); else if (s>mid) update(k<<1|1,s,t,val); else update(k<<1,s,mid,val),update(k<<1|1,mid+1,t,val); tr[k].s=max(tr[k<<1].s,tr[k<<1|1].s); } int query(int k,int p) { int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if (l==r && l==p) return tr[k].s; if (p<=mid) return query(k<<1,p); else return query(k<<1|1,p); }}int main() { using namespace Suffix; using namespace SegTree; scanf("%s",s+1); int n=strlen(s+1); da(s,sa,n,300); calheight(s,sa,n); build(1,1,n); for (int i=1;i<=n;i++) { int val=max(height[rank[i]],height[rank[i]+1]); if (val==n-i+1) continue; update(1,i,i+val,val+1); } for (int i=1;i<=n/2;i++) swap(s[i],s[n-i+1]); da(s,sa,n,300); calheight(s,sa,n); for (int i=1;i<=n;i++) { int val=max(height[rank[i]],height[rank[i]+1]); if (val==n-i+1) continue; update(1,n-(i+val)+1,n-i+1,val+1); } for (int i=1;i<=n;i++) printf("%d\n",min(n,query(1,i))); return 0;}

 

转载于:https://www.cnblogs.com/MashiroSky/p/6284267.html

你可能感兴趣的文章
简明Linux命令行笔记:chmod
查看>>
简明Linux命令行笔记:tar
查看>>
Red and Black(poj-1979)
查看>>
分布式锁的思路以及实现分析
查看>>
vue v-for下图片src显示失败,404错误
查看>>
腾讯元对象存储之文件删除
查看>>
jdk环境变量配置
查看>>
Hbase basic
查看>>
安装 Express
查看>>
包含列的索引:SQL Server索引的阶梯级别5
查看>>
myeclipse插件安装
查看>>
浙江省第十二届省赛 Beauty of Array(思维题)
查看>>
NOIP2013 提高组 Day1
查看>>
个人对vue生命周期的理解
查看>>
cocos2dx 3.x simpleAudioEngine 长音效被众多短音效打断问题
查看>>
存储(硬件方面的一些基本术语)
查看>>
观察者模式
查看>>
转】MyEclipse使用总结——MyEclipse文件查找技巧
查看>>
Weka中数据挖掘与机器学习系列之基本概念(三)
查看>>
Win磁盘MBR转换为GUID
查看>>