H - Repeats (重复最多子串的次数)
题目链接:https://cn.vjudge.net/contest/283743#problem/H
题目大意:T组数据,给你一个字符串,然后让你求这个字符串的重复最多子串的次数。
具体思路:论文题。
https://www.cnblogs.com/staginner/archive/2012/02/06/2340521.html。
rmq处理的是某区间内的最小的前缀长度,这样查询的时候直接找到这个区间内的最小值就可以了。
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 = 5e5+100; 12 int cntA[maxn], cntB[maxn], sa[maxn], tsa[maxn], A[maxn], B[maxn], height[maxn]; 13 int Rank[maxn],dp[25][maxn]; 14 char ch[maxn]; 15 int sto[maxn]; 16 ll n; 17 //sa[i]代表第i小的后缀位置,Rank[i]代表第i位置的后缀,排名第几小 18 // height[i]代表排名第i个字符串和第i-1个字符串的相同前缀有多少个 19 void cal() 20 { 21 for(int i = 0; i < 256; 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 < 256; 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 void rmq() 77 { 78 for(int i=1; i<=n; i++) 79 { 80 dp[0][i]=height[i]; 81 } 82 int tmp=log2(n); 83 for(int i=1; i<=tmp; i++) 84 { 85 for(int j=1; (1<<i)+j-1<=n; j++) 86 { 87 dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<(i-1))]); 88 } 89 } 90 } 91 int query(int t1,int t2) 92 { 93 t1=Rank[t1]; 94 t2=Rank[t2]; 95 if(t1>t2) 96 swap(t1,t2); 97 t1++; 98 int tmp=log2(t2-t1+1); 99 return min(dp[tmp][t1],dp[tmp][t2-(1<<tmp)+1]); 100 } 101 int main() 102 { 103 int T; 104 scanf("%d",&T); 105 while(T--) 106 { 107 char u; 108 scanf("%d",&n); 109 for(int i=0; i<n; i++) 110 { 111 getchar(); 112 scanf("%c",&u); 113 ch[i]=u; 114 } 115 //cout<<ch<<endl; 116 cal(); 117 rmq(); 118 int ans=0,t1,t2,t; 119 for(int i=1; i<=n; i++) 120 { 121 for(int j=1; j+i<=n; j+=i) 122 { 123 int tmp=query(j,j+i); 124 t1=i-tmp%i; 125 t2=j-t1; 126 t=tmp/i+1; 127 if(t2>0&&query(t2,t2+i)>=t1) 128 t++; 129 ans=max(ans,t); 130 } 131 } 132 printf("%d\n",ans); 133 } 134 return 0; 135 }