[Usaco2006 Dec]Milk Patterns
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
Sample Output
4
Source
后缀数组
答案应该是height数组中连续K-1个值的最小值的最大值。
这题还是要先离散化一下,不然可能会MLE
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 30010
using namespace std;
char ch;
int n,k,max_val,tot,head,tail,s[maxn],num[maxn],SA[maxn],rank[maxn],tmp[maxn],sum[maxn],height[maxn];
struct DATA{
int val,tim;
}list[maxn];
inline bool isdigit(char ch){return '0'<=ch&&ch<='9';}
inline void read(int &x){
for (ch=getchar();!isdigit(ch);ch=getchar());
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
}
inline bool cmp(int a,int b){return s[a]<s[b];}
void prepare(){
sort(num+1,num+1+n,cmp);
for (int i=1,pre=-1;i<=n;i++){
if (s[num[i]]!=pre) pre=s[num[i]],++max_val;
s[num[i]]=max_val;
}
}
void get_SA(){
for (int i=1;i<=n;i++) sum[tmp[i]=s[i]]++;
for (int i=1;i<=max_val;i++) sum[i]+=sum[i-1];
for (int i=n;i>=1;i--) SA[sum[tmp[i]]--]=i;
rank[SA[1]]=tot=1;
for (int i=2;i<=n;i++){
if (tmp[SA[i]]!=tmp[SA[i-1]]) tot++;
rank[SA[i]]=tot;
}
for (int len=1;len<=n;len<<=1){
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++) sum[rank[i+len]]++;
for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
for (int i=n;i>=1;i--) tmp[sum[rank[i+len]]--]=i;
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++) sum[rank[tmp[i]]]++;
for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
for (int i=n;i>=1;i--) SA[sum[rank[tmp[i]]]--]=tmp[i];
tmp[SA[1]]=tot=1;
for (int i=2;i<=n;i++){
if (rank[SA[i]]!=rank[SA[i-1]]||rank[SA[i]+len]!=rank[SA[i-1]+len]) tot++;
tmp[SA[i]]=tot;
}
for (int i=1;i<=n;i++) rank[i]=tmp[i];
}
}
void get_height(){
for (int i=1,j=0;i<=n;i++){
if (rank[i]==1) continue;
while (s[i+j]==s[SA[rank[i]-1]+j]) j++;
height[rank[i]]=j;
if (j>0) j--;
}
}
int main(){
read(n),read(k);
for (int i=1;i<=n;i++) read(s[i]),num[i]=i;
prepare(),get_SA(),get_height();
k--,head=1,tail=0,max_val=0;
for (int i=2;i<=n;i++){
while (head<=tail&&i-list[head].tim>=k) head++;
while (head<=tail&&height[i]<list[tail].val) tail--;
list[++tail]=(DATA){height[i],i};
if (i>k&&max_val<list[head].val) max_val=list[head].val;
}
printf("%d\n",max_val);
return 0;
}