[Usaco2006 Dec]Milk Patterns

来源:互联网 发布:淘宝茶叶店 编辑:程序博客网 时间:2024/06/06 20:31

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 212323231

Sample Output

4
思路:和上一题一样,求最长可重叠的重复子串,但多了一个限制,要至少出现k次。二分,按height分组后统计是否有一个组的后缀个数大于k,如果有,那么就表明这一组的公共前缀在原字符串里出现了k次以上,那么就符合要求,return true;
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxl=40010;int sa[maxl],tsa[maxl],rank[maxl],trank[maxl],sum[1000010],n,s[maxl],k,ans,h[maxl];void sorts(int j){memset(sum,0,sizeof(sum));for (int i=1;i<=n;i++) sum[rank[i+j]]++;for (int i=1;i<=n;i++) sum[i]+=sum[i-1];for (int i=n;i;i--) tsa[sum[rank[i+j]]--]=i;memset(sum,0,sizeof(sum));for (int i=1;i<=n;i++) sum[rank[tsa[i]]]++;for (int i=1;i<=n;i++) sum[i]+=sum[i-1];for (int i=n;i;i--) sa[sum[rank[tsa[i]]]--]=tsa[i]; }void getsa(){for (int i=1;i<=n;i++) trank[i]=s[i];for (int i=1;i<=n;i++) sum[trank[i]]++;//for (;;);for (int i=1;i<=1000000;i++) sum[i]+=sum[i-1];for (int i=n;i;i--) sa[sum[trank[i]]--]=i;rank[sa[1]]=1;for (int i=2,p=1;i<=n;i++){if (trank[sa[i]]!=trank[sa[i-1]]) p++;rank[sa[i]]=p;}for (int j=1;j<=n;j*=2){sorts(j);trank[sa[1]]=1;for (int i=2,p=1;i<=n;i++){if (rank[sa[i]]!=rank[sa[i-1]]||rank[sa[i]+j]!=rank[sa[i-1]+j]) p++;trank[sa[i]]=p;}memcpy(rank,trank,sizeof(rank));}}void geth(){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++;h[rank[i]]=j;if (j) j--; }}bool check(int lim){int len=1,maxs=0,mins=100000000;for (int i=2;i<=n;i++){if (h[i]<lim){maxs=0,mins=100000000,len=0;} maxs=max(maxs,sa[i]);mins=min(mins,sa[i]);len++;if (len>=k) return true;}return false;}int main(){scanf("%d%d",&n,&k);for (int i=1;i<=n;i++)scanf("%d",&s[i]);getsa();geth();int l=1,r=20000,mid=(l+r)>>1;while (l<=r){if (check(mid)){l=mid+1;ans=mid;}else r=mid-1;mid=(l+r)>>1;}printf("%d\n",ans);//for (;;);return 0;}


0 0
原创粉丝点击