1. 程式人生 > >[bzoj1717][Usaco2006 Dec]Milk Patterns 產奶的模式_後綴數組_二分答案

[bzoj1717][Usaco2006 Dec]Milk Patterns 產奶的模式_後綴數組_二分答案

觀察 ios 有變 lse 當前 typename 直接 ostream 答案

Milk Patterns 產奶的模式 bzoj-1717 Usaco-2006 Dec

題目大意:給定一個字符串,求最長的至少出現了$k$次的子串長度。

註釋:$1\le n\le 2\cdot 10^4$,$2\le k\le n$。


想法:不難想到二分答案,現在我們考慮如何驗證。

這裏就是後綴數組的一個妙用了。

我們對原串建立後綴數組,觀察$ht$數組。

考慮當前二分出來的$mid$。如果有至少連續$k$的$ht$值都不小於$mid$,那麽$k$就是合法的。

故此我們直接掃$ht$數組看看最長的連續比$mid$大的$ht$有多少個即可。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010 
using namespace std;
int wv[N],wa[N],sa[N],Ws[N],wb[N],t[N],rk[N],ht[N],r[N];
int n,m=1000009;
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
void build_sa()
{
	int i,j,p,*x=wa,*y=wb,*t;
	for(i=0;i<m;i++) Ws[i]=0;
	for(i=0;i<n;i++) Ws[x[i]=r[i]]++;
	for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
	for(i=n-1;~i;i--) sa[--Ws[x[i]]]=i;
	for(p=j=1;p<n;j<<=1,m=p)
	{
		for(p=0,i=n-j;i<n;i++) y[p++]=i;
		for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
		for(i=0;i<n;i++) wv[i]=x[y[i]];
		for(i=0;i<m;i++) Ws[i]=0;
		for(i=0;i<n;i++) Ws[wv[i]]++;
		for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
		for(i=n-1;~i;i--) sa[--Ws[wv[i]]]=y[i];
		for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++)
		{
			if(y[sa[i]]==y[sa[i-1]]&&y[sa[i-1]+j]==y[sa[i]+j]) x[sa[i]]=p-1;
			else x[sa[i]]=p++;
		}
	}
	for(i=1;i<n;i++) rk[sa[i]]=i;
	for(i=p=0;i<n-1;ht[rk[i++]]=p)
		for(p?p--:0,j=sa[rk[i]-1];r[i+p]==r[j+p];p++);
}
template <typename T> void Max(T &x,T y) {x=max(x,y);}
// inline void Max(int &x,int y) {x=max(x,y);}
int check(int x)
{
	int re=-1,now=0;
	for(int i=0;i<n;i++)
	{
		if(ht[i]>=x) now++;
		else Max(re,now),now=1;
	}
	Max(re,now);
	return re;
}
int main()
{
	n=rd();int k=rd(); for(int i=0;i<n;i++) r[i]=rd();
	r[n++]=0; build_sa();
	int l=0,r=n+1;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid)>=k) l=mid+1;
		else r=mid;
	}
	l--;
	cout << l << endl ;
	return 0;
}

小結:後綴數組有很多特別有趣的妙用,要多積累啊!因為開$iostream$的緣故所以不能有變量叫做$ws$,我就叫$Ws$了……

[bzoj1717][Usaco2006 Dec]Milk Patterns 產奶的模式_後綴數組_二分答案