H

题目链接: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
",ans);
133     }
134     return 0;
135 }
原文地址:https://www.cnblogs.com/letlifestop/p/10394145.html