1717: [Usaco2006 Dec]Milk Patterns 产奶的模式
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 903 Solved: 495
[ Submit][ Status][ Discuss]
Description
农夫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。
Input
* Line 1: 两个整数 N,K。
* Lines 2..N+1: 每行一个整数表示当天的质量值。
Output
* Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度
Sample Input
8 2
1
2
3
2
3
2
3
1
1
2
3
2
3
2
3
1
Sample Output
4
HINT
Source
题解:后缀数组解决可重叠的k次最长重复子串。
首先要利用后缀数组求出sa,rank,h (h[i]表示排名第I的后缀与排名i-1的后缀的最长公共前缀)
然后二分答案,判断是否存在连续至少k-1个位置的h值大于mid
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 20003
#define M 1000003
using namespace std;
int n,m,p,q,k;
int a[N],v[M],rank[2][N],sa[2][N],h[N],ht[N];
void solve(int sa[N],int rank[N],int sa1[N],int rank1[N])
{
for (int i=1;i<=n;i++) v[rank[sa[i]]]=i;
for (int i=n;i>=1;i--)
if (sa[i]>k)
sa1[v[rank[sa[i]-k]]--]=sa[i]-k;
for (int i=n-k+1;i<=n;i++)
sa1[v[rank[i]]--]=i;
for (int i=1;i<=n;i++)
rank1[sa1[i]]=rank1[sa1[i-1]]+(rank[sa1[i]]!=rank[sa1[i-1]]||rank[sa1[i]+k]!=rank[sa1[i-1]+k]);
}
void work()
{
p=0; q=1;
for (int i=1;i<=n;i++) v[a[i]]++;
for (int i=1;i<=n;i++) v[i]+=v[i-1];
for (int i=1;i<=n;i++) sa[p][v[a[i]]--]=i;
for (int i=1;i<=n;i++)
rank[p][sa[p][i]]=rank[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
k=1;
while (k<=n)
{
solve(sa[p],rank[p],sa[q],rank[q]);
p^=1; q^=1; k<<=1;
}
}
void calc()
{
int k=0;
for (int i=1;i<=n;i++)
if (rank[p][i]==1) h[rank[p][i]]=0;
else
{
int j=sa[p][rank[p][i]-1];
while (a[i+k]==a[j+k]) k++;
h[rank[p][i]]=k;
if(k>0) k--;
}
}
int check(int x)
{
int num=0;
for (int i=1;i<=n;i++)
if (h[i]>=x)
{
num++;
if (num==m-1) return 1;
}
else num=0;
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]++;
work();
calc();
int head=1; int tail=n;
int ans=0;
while (head<=tail)
{
int mid=(head+tail)/2;
if (check(mid)) ans=mid,head=mid+1;
else tail=mid-1;
}
printf("%d\n",ans);
}