题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12580

 

【思路】

 

       求出现次数不小于k次的最长可重叠子串和最后的出现位置。

       法一:

              后缀数组,二分长度,划分height。时间复杂度为O(nlogn)

       法二:

              Hash法。构造字符串的hash函数,二分长度,求出hash(i,L)后排序,判断是否存在超过k个相同hash 值得块即可。时间为O(nlog2n).

    法三:(UPD.16/4/6)

     SAM。求|right|。

       注意划分height一定要精确且如果m=1需要特判

 

【代码1】

 

 1 //193ms 
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 
 7 const int maxn = 80000+10; 
 8 
 9 int s[maxn];
10 int sa[maxn],c[maxn],t[maxn],t2[maxn];
11 void build_sa(int m,int n) {
12     int i,*x=t,*y=t2;
13     for(i=0;i<m;i++) c[i]=0;
14     for(i=0;i<n;i++) c[x[i]=s[i]]++;
15     for(i=1;i<m;i++) c[i]+=c[i-1];
16     for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
17     for(int k=1;k<=n;k<<=1) {
18         int p=0;
19         for(i=n-k;i<n;i++) y[p++]=i;
20         for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
21         for(i=0;i<m;i++) c[i]=0;
22         for(i=0;i<n;i++) c[x[y[i]]]++;
23         for(i=0;i<m;i++) c[i]+=c[i-1];
24         for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
25         swap(x,y);
26         p=1; x[sa[0]]=0;
27         for(i=1;i<n;i++) 
28             x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
29         if(p>=n) break;
30         m=p;
31     }
32 }
33 int rank[maxn],height[maxn];
34 void getHeight(int n) {
35     int i,j,k=0;
36     for(i=0;i<=n;i++) rank[sa[i]]=i;
37     for(i=0;i<n;i++) {
38         if(k) k--;
39         j=sa[rank[i]-1];
40         while(s[j+k]==s[i+k]) k++;
41         height[rank[i]]=k;
42     }
43 }
44 int limit,n,pos;
45 bool can(int L) {    //一定要注意划分height数组的准确性 
46     pos=-1;
47     int cnt=1,mx=sa[1];
48     for(int i=2;i<=n;i++) {
49         mx=max(mx,sa[i]);
50         if(height[i]<L) cnt=1,mx=sa[i];
51         else {
52             if(++cnt>=limit) pos=max(pos,mx);
53         }
54     }
55     return pos>=0;
56 }
57 
58 char expr[maxn];
59 int main() {
60     //freopen("in.in","r",stdin);
61     //freopen("out.out","w",stdout);
62     while(scanf("%d",&limit)==1 && limit) {
63         scanf("%s",expr);
64         n=strlen(expr);
65         for(int i=0;i<n;i++) s[i]=expr[i]; s[n]=0;
66         
67         build_sa('z'+1,n+1);
68         getHeight(n);
69         
70         if(limit==1) { printf("%d 0\n",n); continue; }
71         int L=1,R=n+1;
72         while(L<R) {
73             int M=L+(R-L+1)/2;
74             if(can(M)) L=M; else R=M-1;
75         }
76         if(!can(L)) printf("none\n");
77         else printf("%d %d\n",L,pos);
78     }
79     return 0;
80 }
da

相关文章:

  • 2021-12-02
  • 2021-08-25
  • 2021-10-20
  • 2021-06-06
  • 2022-12-23
  • 2022-12-23
  • 2022-01-14
  • 2022-12-23
猜你喜欢
  • 2021-07-30
  • 2022-12-23
  • 2021-11-01
  • 2021-09-15
  • 2022-12-23
  • 2022-12-23
  • 2021-08-31
相关资源
相似解决方案