不可重叠最长重复子串

题目链接:https://cn.vjudge.net/contest/318888#overview

题意:给定一个钢琴的音普序列[值的范围是(1~88)],现在要求找到一个子序列满足

1,长度至少为5

2,序列可以转调,即存在两个子序列,满足一个子序列加/减一个数后可以得到另一个序列

3,两个序列不能有相交的部分。

题意简单来说就是找最长不重叠的重复子串

思路:

其实这道题和求最长可重叠最长重复子串很像。我们只要再求最长可重叠最长重复子串的基础上再去判断一下sa[i] 使其不能重合就可以了

  1 #include <stdio.h>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <math.h>
  7 #include <queue>
  8 #include <set>
  9
 10 #define INF 0x3f3f3f3f
 11 #define pii pair<int,int>
 12 #define LL long long
 13 using namespace std;
 14 typedef unsigned long long ull;
 15 const int maxn = 2e6+6;
 16
 17 int s[maxn];
 18 int sa[maxn],t[maxn],t2[maxn],c[maxn];
 19 int Rank[maxn],height[maxn];
 20
 21 void build_sa(int n,int m)
 22 {
 23     int i,j,*x=t,*y=t2;
 24     for (i=0;i<m;i++)
 25         c[i] = 0;
 26     for (i=0;i<n;i++)
 27         c[x[i] = s[i]]++;
 28     for (i=1;i<m;i++)
 29         c[i] += c[i-1];
 30     for (i=n-1;i>=0;i--)
 31         sa[--c[x[i]]] = i;
 32     for (int k=1;k<=n;k<<=1)
 33     {
 34         int p = 0;
 35         for (i=n-k;i<n;i++)
 36             y[p++] = i;
 37         for (i=0;i<n;i++)
 38         {
 39             if (sa[i]>=k)
 40                 y[p++] = sa[i]-k;
 41         }
 42         for (i=0;i<m;i++)
 43             c[i] = 0;
 44         for (i=0;i<n;i++)
 45             c[x[y[i]]]++;
 46         for (i=1;i<m;i++)
 47             c[i] += c[i-1];
 48         for (i=n-1;i>=0;i--)
 49             sa[--c[x[y[i]]]] = y[i];
 50         swap(x,y);
 51         p = 1;
 52         x[sa[0]] = 0;
 53         for (i=1;i<n;i++)
 54             x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 55         if (p>=n)
 56             break;
 57         m = p;
 58     }
 59 }
 60
 61
 62 void getHeight(int n){
 63     int i,j,k=0;
 64     for (i=1;i<=n;i++){
 65         Rank[sa[i]] = i;
 66     }
 67     for (i=0;i<n;i++){
 68         if (k)
 69             k--;
 70         j = sa[Rank[i]-1];
 71         while (s[i+k] == s[j+k])
 72             k++;
 73         height[Rank[i]] = k;
 74     }
 75 }
 76
 77 int n;
 78 bool check(int k){
 79     int maxsa=sa[0],minsa=sa[0];
 80     for (int i=1;i<n;i++){
 81         if (height[i]>=k){
 82             minsa = min(sa[i],minsa);
 83             maxsa = max(sa[i],maxsa);
 84         }
 85         else{
 86             if (maxsa-minsa>=k)
 87                 return true;
 88             maxsa = sa[i];
 89             minsa = sa[i];
 90         }
 91     }
 92     if (maxsa-minsa>=k){
 93         return true;
 94     }
 95     return false;
 96 }
 97
 98 int main(){
 99     while (~scanf("%d",&n) && n!=0){
100         for (int i=0;i<n;i++){
101             scanf("%d",&s[i]);
102         }
103         for (int i=0;i<n;i++){
104             if (i == n-1)
105                 s[i] = 0;
106             else
107                 s[i] = s[i+1]-s[i] + 100;
108         }
109         build_sa(n,200);
110         getHeight(n-1);
111         int l=0,r=n,mid;
112         while (l<=r){
113             mid = (l+r)>>1;
114             if (check(mid)){
115                 l = mid+1;
116             }
117             else{
118                 r = mid-1;
119             }
120         }
121         if (r<4){
122             printf("0\n");
123         }
124         else{
125             printf("%d\n",r+1);
126         }
127     }
128     return 0;
129 }

原文地址:https://www.cnblogs.com/-Ackerman/p/11332815.html

时间: 2024-10-07 11:55:44

不可重叠最长重复子串的相关文章

【POJ1743】不可重叠最长重复子串

题意:求一个字符串里两个不重叠的最长重复子串 代码如下: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 int sa[20010],rank[20010],y[20010],Rsort[20010]; 8 int wr[20010],a[20010],height[20010],n; 9 10

POJ 1743 (后缀数组+不重叠最长重复子串)

题目链接: http://poj.org/problem?id=1743 题目大意:楼教主の男人八题orz.一篇钢琴谱,每个旋律的值都在1~88以内.琴谱的某段会变调,也就是说某段的数可以加减一个旋律范围的值.问这个谱子内最长不重叠的重复部分大小. 解题思路: 网上题解已经泛滥的题.很多细节都被先辈大神总结了. 在当年后缀数组还不是热门的时候,这题确实是神题. 首先对于旋律变调的处理: 比如123,123,ans=3. 变调之后:456,123,ans=0?不ans=3. 所以不能使用旋律的初始

POJ - 1743 Musical Theme (后缀数组求不可重叠最长重复子串)

Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of music

可重叠最长重复子串

Zvonko收到一条信息,是一个长长的字符串.抛开信息传递的内容,Zvonko发现这个字符串的某些子串,出现了不止一次.他写下所有的子串,想要知道,在字符串中出现至少两次的所有子串中,长度最长的为多少. 就请你写一个程序帮助他吧! Input输入数据第一行包含一个整数L(1≤L≤200000),为给出的原串的长度. 第二行包含一个仅由小写字符组成的,长度为L的字符串. Output输出最长的重复出现的字串的长度.如果这个串不存在,则输出0. Sample Input11sabcabcfabc S

POJ 1743 Musical Theme 后缀数组 不可重叠最长重复子串

二分长度k 长度大于等于k的分成一组 每组sa最大的和最小的距离大于k 说明可行 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 20010; int s[maxn]; int sa[maxn]; int t[maxn], t2[maxn], c[maxn]; int rank[maxn], height[maxn]; void

POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)

Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14094   Accepted: 6244 Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation,

POJ 3261 可重叠的 k 次最长重复子串【后缀数组】

这也是一道例题 给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠.算法分析:这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组.不同的是,这里要判断的是有没有一个组的后缀个数不小于 k.如果有,那么存在k 个相同的子串满足条件,否则不存在.这个做法的时间复杂度为 O(nlogn). Source Code: //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include

POJ - 3261 Milk Patterns (后缀数组求可重叠的 k 次最长重复子串)

Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can't predict the quality of milk from one day to the next, there are some regular pattern

poj 3261 求可重叠的k次最长重复子串

题意:求可重叠的k次最长重复子串的长度 链接:点我 和poj1743差不多 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000