【bzoj1717】[Usaco2006 Dec]Milk Patterns 产奶的模式 SA+二分
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
题解
求出相邻lcp后,二分长度,判断相邻的是不是连续超过k个即可。
为什么这样是对的。
因为两串相同的最长超过k的长度,那么绝对是相邻lcp超过k次对吧,脑补。
1 #include<cstring> 2 #include<cmath> 3 #include<cstdio> 4 #include<algorithm> 5 #include<iostream> 6 7 #define N 20007 8 using namespace std; 9 inline int read() 10 { 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 17 int n,k; 18 int s[N],sa[N],rk[N*2],A[N]; 19 int a[N],b[N],cnta[N],cntb[N],tsa[N],height[N]; 20 21 void Get_SA() 22 { 23 for (int i=1;i<=n;i++)cnta[i]=0; 24 for (int i=1;i<=n;i++)cnta[s[i]]++; 25 for (int i=1;i<=n;i++)cnta[i]+=cnta[i-1]; 26 for (int i=n;i>=1;i--)sa[cnta[s[i]]--]=i; 27 rk[sa[1]]=1; 28 for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]); 29 for (int i=1;rk[sa[n]]!=n;i<<=1) 30 { 31 for (int j=1;j<=n;j++)a[j]=rk[j],b[j]=rk[j+i]; 32 for (int j=0;j<=n;j++)cnta[j]=cntb[j]=0; 33 for (int j=1;j<=n;j++)cnta[a[j]]++,cntb[b[j]]++; 34 for (int j=1;j<=n;j++)cnta[j]+=cnta[j-1],cntb[j]+=cntb[j-1]; 35 for (int j=n;j>=1;j--)tsa[cntb[b[j]]--]=j; 36 for (int j=n;j>=1;j--)sa[cnta[a[tsa[j]]]--]=tsa[j]; 37 rk[sa[1]]=1; 38 for (int j=2;j<=n;j++) 39 rk[sa[j]]=rk[sa[j-1]]+(a[sa[j]]!=a[sa[j-1]]||b[sa[j]]!=b[sa[j-1]]); 40 } 41 } 42 void Get_Height() 43 { 44 int len=0; 45 for (int i=1;i<=n;i++) 46 { 47 if (len) len--; 48 while(s[i+len]==s[sa[rk[i]-1]+len])len++; 49 height[rk[i]]=len; 50 } 51 } 52 bool check(int x) 53 { 54 int tot=0; 55 for (int i=2;i<=n;i++) 56 { 57 if (height[i]>=x)tot++;else tot=0; 58 if (tot>=k-1)return 1; 59 } 60 return 0; 61 } 62 int mid_find(int l,int r) 63 { 64 while(l<r) 65 { 66 int mid=(l+r+1)>>1; 67 if (check(mid))l=mid; 68 else r=mid-1; 69 } 70 return l; 71 } 72 int main() 73 { 74 n=read(),k=read(); 75 for (int i=1;i<=n;i++) A[i]=s[i]=read(); 76 sort(A+1,A+n+1); 77 int cnt=n;cnt=unique(A+1,A+cnt+1)-A-1; 78 for (int i=1;i<=n;i++) 79 s[i]=lower_bound(A+1,A+cnt+1,s[i])-A; 80 Get_SA(); 81 Get_Height(); 82 /*for (int i=1;i<=n;i++)cout<<height[i]<<" "; 83 cout<<endl;*/ 84 printf("%d\n",mid_find(0,n)); 85 }