D - Milk Patterns (出现k次可重复的最长子串的长度)
题目链接:https://cn.vjudge.net/contest/283743#problem/D
题目大意:给你n个数,然后问你出现m次的最长子串的长度。
具体思路:和上一篇博客的内容差不多,这个是可重复的,就不需要考虑sa的问题了,每一次还是二分答案,判断出现的最长前缀就可以了。注意二分的时候,每一次的寻找,初始值为1,因为这个字符串就已经出现过一次了。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<cstring> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<algorithm> 7 #include<cmath> 8 using namespace std; 9 # define ll long long 10 # define inf 0x3f3f3f3f 11 const int maxn = 5e6+100; 12 int cntA[maxn], cntB[maxn], sa[maxn], tsa[maxn], A[maxn], B[maxn], height[maxn]; 13 int Rank[maxn]; 14 int ch[maxn]; 15 int sto[maxn]; 16 ll n,m; 17 //sa[i]代表第i小的后缀位置,Rank[i]代表第i位置的后缀,排名第几小 18 // height[i]代表排名第i个字符串和第i-1个字符串的相同前缀有多少个 19 void cal(int maxx) 20 { 21 for(int i = 0; i <=maxx; i++) 22 cntA[i] = 0; 23 // cout<<1<<endl; 24 // cout<<n<<endl; 25 for(int i = 1; i <= n; i++) 26 { 27 //cout<<ch[i-1]<<endl; 28 cntA[ch[i-1]]++; 29 } 30 // cout<<1<<endl; 31 for(int i = 1; i <= maxx; i++) 32 cntA[i] += cntA[i-1]; 33 for(int i = n; i; i--) 34 sa[cntA[ch[i-1]]--] = i; 35 Rank[sa[1]] = 1; 36 for(int i = 2; i <= n; i++) 37 { 38 Rank[sa[i]] = Rank[sa[i-1]]; 39 if(ch[sa[i]-1] != ch[sa[i-1]-1]) 40 Rank[sa[i]]++; 41 } 42 for(int l = 1; Rank[sa[n]] < n; l <<= 1) 43 { 44 memset(cntA, 0, sizeof(cntA)); 45 memset(cntB, 0, sizeof(cntB)); 46 for(int i = 1; i <= n; i++) 47 { 48 cntA[A[i] = Rank[i]]++; 49 cntB[B[i] = (i+l <= n)?Rank[i+l]:0]++; 50 } 51 for(int i = 1; i <= n; i++) 52 cntB[i] += cntB[i-1]; 53 for(int i = n; i; i--) 54 tsa[cntB[B[i]]--] = i; 55 for(int i = 1; i <= n; i++) 56 cntA[i] += cntA[i-1]; 57 for(int i = n; i; i--) 58 sa[cntA[A[tsa[i]]]--] = tsa[i]; 59 Rank[sa[1]]=1; 60 for(int i = 2; i <= n; i++) 61 { 62 Rank[sa[i]] = Rank[sa[i-1]]; 63 if(A[sa[i]] != A[sa[i-1]] || B[sa[i]] != B[sa[i-1]]) 64 Rank[sa[i]]++; 65 } 66 } 67 for(int i = 1, j = 0; i <= n; i++) 68 { 69 if(j) 70 j--; 71 while(ch[i+j-1] == ch[sa[Rank[i]-1] + j - 1]) 72 j++; 73 height[Rank[i]] = j; 74 } 75 } 76 bool judge(int t) 77 { 78 int ans=1; 79 for(int i=2; i<=n; i++) 80 { 81 if(height[i]>=t) 82 { 83 ans++; 84 } 85 else 86 { 87 ans=1; 88 } 89 if(ans>=m) 90 return true; 91 } 92 return false; 93 } 94 int main() 95 { 96 int maxx=0; 97 scanf("%lld %lld",&n,&m); 98 for(int i=1; i<=n; i++) 99 { 100 scanf("%d",&ch[i]); 101 maxx=max(maxx,ch[i]); 102 } 103 cal(maxx); 104 int l=0,r=1e8,ans=0; 105 while(l<=r) 106 { 107 int mid=(l+r)>>1; 108 if(judge(mid)) 109 { 110 ans=mid; 111 l=mid+1; 112 } 113 else 114 { 115 r=mid-1; 116 } 117 } 118 printf("%d\n",ans); 119 return 0; 120 }