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 }

 

posted @ 2019-02-17 09:38  Let_Life_Stop  阅读(307)  评论(0编辑  收藏  举报