POJ 1743 - Musical Theme 最长不重叠重复子串

题意:
    给出一列数据,问你其中重复的最长连续子串的长度
    但是有要求:
        1. 长度至少为 5 .
        2. 两串可以不相等,但两串每个对应位置的数字相减差值固定 (即相同变化)

分析:
    因为子串变化相同,故可先把原数组前后相减, 则求出差值数组的最长重复子串的长度再 +1 就是答案.
    
    最长重复子串的长度:
        使用后缀数组.
        先将问题变为判定是否存在长度为 x 的重复子串,再用二分寻找答案.
        用 height数组 将长度大于 x 的划为同区,则每个区里的每个后缀的公共前缀至少为 x
        再找每个区的后缀的 sa 的最大值和最小值,若最大值和最小值之差不小于x,那两个后缀的公共前缀则不重叠,即有解
   

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int MAXN = 20010;
 6 struct SuffixArray
 7 {
 8     int wa[MAXN], wb[MAXN], wsf[MAXN], wv[MAXN];
 9     
10     int Cmp(int r[], int a, int b, int k)
11     {
12         return r[a] == r[b] && r[a+k] == r[b+k];
13     }
14     void GetSa(int r[], int sa[], int n, int m)
15     {
16         int i, j, p, *x = wa, *y = wb, *t;
17         for (i = 0; i < m; i++)  wsf[i] = 0;
18         for (i = 0; i < n; i++)  wsf[x[i]=r[i]]++;
19         for (i = 1; i < m; i++)  wsf[i] += wsf[i-1];
20         for (i = n-1; i >= 0; i--)  sa[--wsf[x[i]]] = i;
21         for (p = j = 1; p < n; j *= 2, m = p) {
22             for (p = 0, i = n - j; i < n; i++)  y[p++] = i;
23             for (i = 0; i < n; i++)  if(sa[i] >= j)  y[p++] = sa[i] - j;
24             for (i = 0; i < n; i++)  wv[i] = x[y[i]];
25             for (i = 0; i < m; i++)  wsf[i] = 0;
26             for (i = 0; i < n; i++)  wsf[wv[i]]++;
27             for (i = 1; i < m; i++)  wsf[i] += wsf[i-1];
28             for (i = n-1; i >= 0; i--)  sa[--wsf[wv[i]]] = y[i];
29             swap(x, y);
30             x[sa[0]] = 0;
31             for (p = i = 1; i < n; i++)
32                 x[sa[i]] = Cmp(y, sa[i-1], sa[i], j) ? p - 1 : p++;
33         }
34     }
35     void GetHeight(int r[], int sa[], int rnk[], int height[], int n)
36     {
37         int i, j, k = 0;
38         for (i = 1; i <= n; i++)  
39             rnk[sa[i]] = i;
40         for (i = 0; i < n; i++)
41         {
42             if (k) k--;
43             j = sa[rnk[i]-1];
44             while (r[i+k] == r[j+k]) k++;
45             height[rnk[i]] = k;
46         }
47     }
48 }suffixArray;
49 int r[MAXN], sa[MAXN], rnk[MAXN], height[MAXN];
50 int s[MAXN];
51 int n;
52 
53 bool Query(int x)
54 {
55     int Min, Max;
56     Min = Max = sa[1];
57     for(int i = 2; i < n; i++)
58     {
59         if(height[i] >= x)
60         {
61             Min = min(Min, sa[i]);
62             Max = max(Max, sa[i]);
63             if(Max - Min >= x) return 1;
64         }
65         else Min = Max = sa[i];
66     }
67     return 0;
68 }
69 int solve(int l,int r)
70 {
71     int mid,pos;
72     while(l<=r)
73     {
74         int mid=(l+r)>>1;
75         if(Query(mid)) pos=mid,l=mid+1;
76         else r=mid-1;
77     }
78     return pos;
79 }
80 int main()
81 {
82     while(~scanf("%d",&n) && n)
83     {
84         for (int i = 0; i < n; i++) scanf("%d",&s[i]);
85         n--;
86         for (int i = 0; i < n; i++)
87             r[i] = s[i+1] - s[i] + 100;
88         r[n] = 0;
89         suffixArray.GetSa(r,sa,n+1,200);
90         suffixArray.GetHeight(r,sa,rnk,height,n);
91         int l = 0, r = n;
92         int ans = solve(l, r) + 1;
93         printf("%d\n", ans < 5 ? 0 : ans);
94     }
95 }

 

转载于:https://www.cnblogs.com/nicetomeetu/p/5763236.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值