bzoj1717
[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
1
2
3
2
3
2
3
1
Sample Output
4
*******************************************************************************************************************************************
题意:给定长为N的数组,问重复次数不小于K的最长区间长度。
首先,我们应该了解到所有后缀的前缀就是所有的子串。所以,相同子串那么他们的rank[]一定相临。想长度大小就是height[].
所以,height[]中连续连续k个数中最小值最大。所以二分值的大小,依次判断就可以了。
应该用单调队列也可以了,没有试过。
***********************************************************************************************
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=20010; 4 int s[maxn],sa[maxn],rank[maxn],saf[maxn],cs[maxn],height[maxn]; 5 int n,m,cc,kk; 6 void init() 7 { 8 scanf("%d%d",&n,&cc); 9 for(int i=1;i<=n;++i)scanf("%d",&s[i]),m=max(m,s[i]); 10 s[0]=s[n+1]=-1; 11 } 12 void rsort() 13 { 14 for(int i=0;i<=m;++i)cs[i]=0; 15 for(int i=1;i<=n;++i)cs[rank[saf[i]]]++; 16 for(int i=1;i<=m;++i)cs[i]+=cs[i-1]; 17 for(int i=n;i>=1;--i)sa[cs[rank[saf[i]]]--]=saf[i]; 18 } 19 int cmp(int *f,int x,int y,int w) 20 { 21 return f[x]==f[y] && f[x+w]==f[y+w]; 22 } 23 void suffix() 24 { 25 for(int i=1;i<=n;++i)rank[i]=s[i],saf[i]=i; 26 rsort(); 27 for(int p=1,w=1,i;p<n;w<<=1,m=p) 28 { 29 for(i=n-w+1,p=0;i<=n;++i)saf[++p]=i; 30 for(i=1;i<=n;++i)if(sa[i]>w)saf[++p]=sa[i]-w; 31 rsort();swap(rank,saf);rank[sa[1]]=p=1; 32 for(int i=2;i<=n;++i)rank[sa[i]]=cmp(saf,sa[i],sa[i-1],w)?p:++p; 33 } 34 int j,k=0; 35 for(int i=1;i<=n;height[rank[i++]]=k) 36 for(k=k?k-1:k,j=sa[rank[i]-1];s[i+k]==s[j+k];++k); 37 } 38 bool pd(int x) 39 { 40 int num=0; 41 for(int i=1;i<=n;++i) 42 { 43 if(height[i]>=x) 44 { 45 num++; 46 if(num>=cc-1)return 1; 47 } 48 else num=0; 49 } 50 return 0; 51 } 52 int main() 53 { 54 init(); 55 suffix(); 56 int l=1,r=n,ans; 57 while(l<=r) 58 { 59 int mid=(l+r)>>1; 60 if(pd(mid))ans=mid,l=mid+1; 61 else r=mid-1; 62 } 63 cout<<ans; 64 return 0; 65 }