BZOJ1396 识别子串 和 BZOJ2865 字符串识别

字符串识别

<body> <center><h2>2865: 字符串识别</h2><span class="green">Time Limit: </span>10 Sec&nbsp;&nbsp;<span class="green">Memory Limit: </span>128 MB<br><span class="green">Submit: </span>839&nbsp;&nbsp;<span class="green">Solved: </span>261<br>[<a href="submitpage.php?id=2865">Submit</a>][<a href="problemstatus.php?id=2865">Status</a>][<a href="bbs.php?id=2865">Discuss</a>]</center><h2>Description</h2><div class="content"><p class="NOI1" style="margin: 13pt 0cm"></p> <p class="NOI" style="margin: 0cm 0cm 0pt"><font size="3"><span lang="EN-US"><font face="Times New Roman">XX</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在进行字符串研究的时候,遇到了一个十分棘手的问题。</span></font></p> <p class="NOI" style="margin: 0cm 0cm 0pt"><font size="3"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在这个问题中,给定一个字符串</span><span lang="EN-US"><font face="Times New Roman">S</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,与一个整数</span><span lang="EN-US"><font face="Times New Roman">K</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,定义</span><span lang="EN-US"><font face="Times New Roman">S</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的子串</span><span lang="EN-US"><font face="Times New Roman">T=S(i, j)</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是关于第</span><span lang="EN-US"><font face="Times New Roman">K</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">位的识别子串,满足以下两个条件:</span></font></p> <p class="NOI" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1"><font size="3"><font face="Times New Roman"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore">1、</span></span><span lang="EN-US">i</span></font><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">≤</span><span lang="EN-US"><font face="Times New Roman">K</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">≤</span><span lang="EN-US"><font face="Times New Roman">j</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span></font></p> <p class="NOI" style="margin: 0cm 0cm 0pt; mso-list: l0 level1 lfo1"><font size="3"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore"><font face="Times New Roman">2、</font></span></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子串</span><span lang="EN-US"><font face="Times New Roman">T</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">只在</span><span lang="EN-US"><font face="Times New Roman">S</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中出现过一次。</span></font></p> <p class="NOI" style="margin: 0cm 0cm 0pt; text-indent: 0cm; mso-char-indent-count: 0"><font size="3"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">例如,</span><span lang="EN-US"><font face="Times New Roman">S="banana"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</span><span lang="EN-US"><font face="Times New Roman">K=5</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,则关于第</span><span lang="EN-US"><font face="Times New Roman">K</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">位的识别子串有</span><span lang="EN-US"><font face="Times New Roman">"nana"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</span><span lang="EN-US"><font face="Times New Roman">"anan"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</span><span lang="EN-US"><font face="Times New Roman">"anana"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</span><span lang="EN-US"><font face="Times New Roman">"nan"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</span><span lang="EN-US"><font face="Times New Roman">"banan"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span><span lang="EN-US"><font face="Times New Roman">"banana"</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span></font></p> <p class="NOI" style="margin: 0cm 0cm 0pt; text-indent: 0cm; mso-char-indent-count: 0"><font size="3"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">现在,给定</span><span lang="EN-US"><font face="Times New Roman">S</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">,</span><span lang="EN-US"><font face="Times New Roman">XX</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">希望知道对于</span><span lang="EN-US"><font face="Times New Roman">S</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的每一位,最短的识别子串长度是多少,请你来帮助他。</span></font></p> <p></p></div><h2>Input</h2><div class="content"><p class="NOI" style="margin: 0cm 0cm 0pt"><font size="3"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">仅一行,输入长度为</span><span lang="EN-US"><font face="Times New Roman">N</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的字符串</span><span lang="EN-US"><font face="Times New Roman">S</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span></font></p> <p class="NOI" style="margin: 0cm 0cm 0pt"><span lang="EN-US" style="font-size: 12pt; font-family: 'Courier New'; mso-bidi-font-size: 10.0pt"><o:p></o:p></span></p></div><h2>Output</h2><div class="content"><p class="NOI" style="margin: 0cm 0cm 0pt"><font size="3"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">输出</span><span lang="EN-US"><font face="Times New Roman">N</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">行,每行一个整数,第</span><span lang="EN-US"><font face="Times New Roman">i</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">行的整数表示对于第</span><span lang="EN-US"><font face="Times New Roman">i</font></span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">位的最短识别子串长度。</span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span lang="EN-US" style="font-size: 12pt; font-family: 'Courier New'; mso-bidi-font-size: 10.0pt"><o:p></o:p></span></p></div><h2>Sample Input</h2> <div class="content"><span class="sampledata">agoodcookcooksgoodfood<br> <br> </span></div><h2>Sample Output</h2> <div class="content"><span class="sampledata"><br> 1<br> 2<br> 3<br> 3<br> 2<br> 2<br> 3<br> 3<br> 2<br> 2<br> 3<br> 3<br> 2<br> 1<br> 2<br> 3<br> 3<br> 2<br> 1<br> 2<br> 3<br> 4<br> </span></div><h2>HINT</h2> <div class="content"><p></p><p>N&lt;=5*10^5</p><p></p></div><h2>Source</h2> <div class="content"><p><a href="problemset.php?search="></a></p></div><center>[<a href="submitpage.php?id=2865">Submit</a>][<a href="problemstatus.php?id=2865">Status</a>][<a href="bbs.php?id=2865">Discuss</a>]</center><br> <a href="./"><span class="red">HOME</span></a> <a href="javascript:history.go(-1)"><span class="red">Back</span></a> <hr> </body>

jklover的题解

SAM + 线段树.

先建出 parent 树,按照题意,我们只需要处理 right 集合大小为 1 的节点.
如下图,先算出这样的一个节点合法长度的 max,min ( min 可以用 max(fa)+1 计算).

![](https://jkloverdcoi.github.io/2019/04/27/bzoj-1396-%E8%AF%86%E5%88%AB%E5%AD%90%E4%B8%B2/1.png)
那么区域 I 内每个点的贡献就是区域 II 的长度加上这个点到区域 II 的距离. 区域 II 内每个点的贡献就是区间 II 的长度.开两颗线段树分别修改就可以了.

如何维护区域1呢?考虑他的答案是pos[u]-i+1,直接更新pos[u],那么把最终线段树上的值-i就是答案了。这种操作比较常见。

时间复杂度\(O(n \log n)\)

co int N=2e5,INF=0x3f3f3f3f;
struct node{int min,tag;};
#define lc (x<<1)
#define rc (x<<1|1)
struct SegTree{
	node t[N*4];
	void pushup(int x){
		t[x].min=min(t[lc].min,t[rc].min);
	}
	void modify(int x,int v){
		t[x].min=min(t[x].min,v),t[x].tag=min(t[x].tag,v);
	}
	void pushdown(int x){
		if(t[x].tag<INF){
			modify(lc,t[x].tag),modify(rc,t[x].tag);
			t[x].tag=INF;
		}
	}
	void build(int x,int l,int r){
		t[x].min=t[x].tag=INF;
		if(l==r) return;
		int mid=l+r>>1;
		build(lc,l,mid),build(rc,mid+1,r);
	}
	void update(int x,int l,int r,int ql,int qr,int v){
		if(ql<=l&&r<=qr) return modify(x,v);
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid) update(lc,l,mid,ql,qr,v);
		if(qr>mid) update(rc,mid+1,r,ql,qr,v);
		pushup(x);
	}
}T1,T2;
int ans[N];
void query(int x,int l,int r){
	if(l==r) return ans[l]=min(T1.t[x].min-l,T2.t[x].min),void();
	T1.pushdown(x),T2.pushdown(x);
	int mid=l+r>>1;
	query(lc,l,mid),query(rc,mid+1,r);
}
// SAM
char buf[N];
int n,tot=1,last=1;
int ch[N][26],fa[N],len[N],pos[N],siz[N];
void extend(int c,int po){
	int p=last,cur=last=++tot;
	len[cur]=len[p]+1,pos[cur]=po,siz[cur]=1;
	for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
	if(!p) fa[cur]=1;
	else{
		int q=ch[p][c];
		if(len[q]==len[p]+1) fa[cur]=q;
		else{
			int clone=++tot;
			memcpy(ch[clone],ch[q],sizeof ch[q]);
			fa[clone]=fa[q],len[clone]=len[p]+1,pos[clone]=pos[q];
			fa[q]=fa[cur]=clone;
			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
		}
	}
}
int cnt[N],ord[N];
int main(){
	scanf("%s",buf+1),n=strlen(buf+1);
	for(int i=1;i<=n;++i) extend(buf[i]-'a',i);
	for(int i=1;i<=tot;++i) ++cnt[len[i]];
	for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
	for(int i=1;i<=tot;++i) ord[cnt[len[i]]--]=i;
	T1.build(1,1,n),T2.build(1,1,n);
	for(int i=tot;i>=1;--i){
		int u=ord[i];
		siz[fa[u]]+=siz[u];
		if(u==1||siz[u]>1) continue;
		int l=pos[u]-len[u]+1,r=pos[u]-len[fa[u]];
		if(l<=r-1) T1.update(1,1,n,l,r-1,pos[u]+1);
		T2.update(1,1,n,r,pos[u],len[fa[u]]+1);
	}
	query(1,1,n);
	for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
	return 0;
}

posted on 2019-05-03 15:53  autoint  阅读(125)  评论(0编辑  收藏  举报

导航