农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。
农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。
* Line 1: 两个整数 N,K。
* Lines 2..N+1: 每行一个整数表示当天的质量值。
* Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度
Gold
【分析】
后缀数组+二分答案
观察到如果i为可行长度,那么1~i一定都是可行长度(废话),所以我们可以二分最长长度,每次扫一遍height数组,如果满足连续K-1个height>=mid(二分的长度),那么mid就是一个可行解~
【代码】
//bzoj 1717 [Usaco2006 Dec]Milk Patterns 产奶的模式
#include
#include
#include
#include
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=20005;
int n,m,K,len;
char s[mxn];
int a[mxn],b[1000005],x[mxn],y[mxn],sa[mxn],rank[mxn],height[mxn];
inline bool comp(int i,int j,int l)
{
return y[i]==y[j]&&(i+l>len?-1:y[i+l])==(j+l>len?-1:y[j+l]);
}
inline void work()
{
int i,j,k,p;m=1000000;
fo(i,0,m) b[i]=0;
fo(i,1,len) b[x[i]=a[i]]++;
fo(i,1,m) b[i]+=b[i-1];
for(i=len;i>=1;i--) sa[b[x[i]]--]=i;
for(k=1;k<=len;k<<=1)
{
p=0;
fo(i,len-k+1,len) y[++p]=i;
fo(i,1,len) if(sa[i]>k) y[++p]=sa[i]-k;
fo(i,0,m) b[i]=0;
fo(i,1,len) b[x[y[i]]]++;
fo(i,1,m) b[i]+=b[i-1];
for(i=len;i>=1;i--) sa[b[x[y[i]]]--]=y[i];
swap(x,y),p=2,x[sa[1]]=1;
fo(i,2,len)
x[sa[i]]=comp(sa[i-1],sa[i],k)?p-1:p++;
if(p>len) break;
m=p;
}
p=k=0;
fo(i,1,len) rank[sa[i]]=i;
for(i=1;i<=len;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
}
inline bool ok(int mid)
{
int cnt=1,i,j;
fo(i,2,len)
{
if(height[i]=K) return 1;
}
return 0;
}
int main()
{
int i,j;
scanf("%d%d",&len,&K);
fo(i,1,len) scanf("%d",&a[i]);
work();
int l=1,r=len;
while(l>1;
if(ok(mid)) l=mid;
else r=mid-1;
}
printf("%d\n",l);
return 0;
}
//Have I found you? Flightless bird,jealous weeping.
//or lost you? American mouth.Big pill,looming.