poj 1743 后缀数组 求最长不重叠重复子串

题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。
 “主题”是整个音符序列的一个子串,它需要满足如下条件:
1.长度至少为5个音符
2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。)
3.重复出现的同一主题不能有公共部分。

链接:点我
先转化成相邻两项的差值,然后就是找不可重叠重复子串。
做法就是二分答案LEN
然后根据height值进行分组

第一道后缀数组题,测了一下模板

  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 1000000007
 10 const int INF=0x3f3f3f3f;
 11 const double eps=1e-5;
 12 typedef long long ll;
 13 #define cl(a) memset(a,0,sizeof(a))
 14 #define ts printf("*****\n");
 15 int n,m,tt;
 16 /*
 17 *suffix array
 18 *倍增算法 O(n*logn)
 19 *待排序数组长度为n,放在0~n-1中,在最后面补一个0
 20 *da(str ,n+1,sa,rank,height, , );//注意是n+1;
 21 *例如:
 22 *n = 8;
 23 *num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0
 24 *rank[] = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值
 25 *sa[] = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值
 26 *height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值
 27 *
 28 */
 29 const int MAXN=20010;
 30
 31 char str[MAXN];
 32 int r[MAXN];
 33 int sa[MAXN];
 34 int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值
 35 //待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,
 36 //除s[n-1]外的所有s[i]都大于0,r[n-1]=0
 37 //函数结束以后结果放在sa数组中
 38 bool cmp(int *r,int a,int b,int l)
 39 {
 40     return r[a] == r[b] && r[a+l] == r[b+l];
 41 }
 42 void da(int str[],int sa[],int rank[],int height[],int n,int m)
 43 {
 44     n++;
 45     int i, j, p, *x = t1, *y = t2;
 46     //第一轮基数排序,如果s的最大值很大,可改为快速排序
 47     for(i = 0;i < m;i++)c[i] = 0;
 48     for(i = 0;i < n;i++)c[x[i] = str[i]]++;
 49     for(i = 1;i < m;i++)c[i] += c[i-1];
 50     for(i = n-1;i >= 0;i--)sa[--c[x[i]]] = i;
 51     for(j = 1;j <= n; j <<= 1)
 52     {
 53         p = 0;
 54         //直接利用sa数组排序第二关键字
 55         for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小
 56         for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;
 57         //这样数组y保存的就是按照第二关键字排序的结果
 58         //基数排序第一关键字
 59         for(i = 0; i < m; i++)c[i] = 0;
 60         for(i = 0; i < n; i++)c[x[y[i]]]++;
 61         for(i = 1; i < m;i++)c[i] += c[i-1];
 62         for(i = n-1; i >= 0;i--)sa[--c[x[y[i]]]] = y[i];
 63         //根据sa和x数组计算新的x数组
 64         swap(x,y);
 65         p = 1; x[sa[0]] = 0;
 66         for(i = 1;i < n;i++)
 67         x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
 68         if(p >= n)break;
 69         m = p;//下次基数排序的最大值
 70     }
 71     int k = 0;
 72     n--;
 73     for(i = 0;i <= n;i++)rank[sa[i]] = i;
 74     for(i = 0;i < n;i++)
 75     {
 76         if(k)k--;
 77         j = sa[rank[i]-1];
 78         while(str[i+k] == str[j+k])k++;
 79         height[rank[i]] = k;
 80     }
 81 }
 82 int rank[MAXN],height[MAXN];
 83 int s[MAXN];
 84 bool check(int n,int k)
 85 {
 86     int Max=sa[1],Min=sa[1];
 87     for(int i=2;i<=n;i++)
 88     {
 89         if(height[i]<k)Max=Min=sa[i];
 90         else
 91         {
 92             if(sa[i]<Min)Min=sa[i];
 93             if(sa[i]>Max)Max=sa[i];
 94             if(Max-Min>k)return true;
 95         }
 96     }
 97     return false;
 98 }
 99 int main()
100 {
101     #ifndef ONLINE_JUDGE
102     freopen("1.in","r",stdin);
103     #endif
104     while(scanf("%d",&n)==1 && n)
105     {
106         for(int i=0;i<n;i++)scanf("%d",&s[i]);
107         for(int i=n-1;i>0;i--)s[i]=s[i]-s[i-1]+90;
108         n--;//减少一个长度
109         for(int i=0;i<n;i++)s[i]=s[i+1];
110         s[n]=0;
111         da(s,sa,rank,height,n,200);
112         int ans=-1;
113         int l=1,r=n/2;
114         while(l<=r)
115         {
116             int mid=(l+r)/2;
117             if(check(n,mid))
118             {
119                 ans=mid;
120                 l=mid+1;
121             }
122             else r=mid-1;
123         }
124         if(ans<4)printf("0\n");
125         else printf("%d\n",ans+1);
126     }
127 return 0;
128 }
时间: 2024-10-24 10:46:03

poj 1743 后缀数组 求最长不重叠重复子串的相关文章

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

题意: 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题. "主题"是整个音符序列的一个子串,它需要满足如下条件: 1.长度至少为5个音符 2.在乐曲中重复出现(可能经过转调,"转调"的意思是主题序列中每个音符都被加上或减去了同一个整数值.) 3.重复出现的同一主题不能有公共部分. 思路:是要求最长不重叠重复的子串,如果没有不重叠的限制条件,那么height中的最大值即可 现在对于

poj 1743 最长不重叠重复子串 后缀数组+lcp+二分

题比较容易读懂,但是建模需动点脑子: 一个子串加常数形成的子串认为跟子串相同,求最长不重叠重复子串 题目中说 is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s) 意味着不能重叠,举个例子 1, 2,3,  52, 53,54 1,2, 3和 52, 53,54满足题意,差值为51 枚举差值肯定不行------看了题解明白的:: 后项减去前一项得到: 1,1,1,49,1,1  

POJ 1743 后缀数组:求最长不重叠子串

数据:这题弄了好久,WA了数十发,现在还有个例子没过,可却A了,POJ 的数组也太弱了. 10 1 1 1 1 1 1 1 1 1 1 这组数据如果没有那个n-1<10判断的话,输入的竟然是5,我靠-- 思路:这个题目关键的地方有两个:第一,重复的子串一定可以看作是某两个后缀的公共前缀,第二,把题目转化成去判定对于任意的一个长度k,是否存在长度至少为k的不重叠的重复的子串. 转化成判定问题之后,就可以二分去解答了.在验证判定是否正确时,我们可以把相邻的所有不小于k的height[]看成一组,然后

【hiho】120 后缀数组一&#183;重复旋律2【字符串--后缀数组--最长不可重叠重复子串问题】

传送门:后缀数组一·重复旋律2 题意 最长可重叠重复子串问题 思路 二分答案,转化成判定问题. 看看能不能找出不重叠的重复子串.对于每一组,我们检查这些后缀对应的sa值(也就是后缀起点在原串中的位置i).如果max{sa} - min{sa} >= k,那么就说明我们能找出一组不重叠的重复子串 AC Code #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; c

POJ - 1743 后缀数组 height分组

题意:求最长不可重叠的相同差值子串的长度 这道题算是拖了好几个月,现在花了点时间应该搞懂了不少,尝试分析一下 我们首先来解决一个退化的版本,求最长不可重叠的相同子串(差值为0) 比如\(aabaabaa\), 那么所求的子串有\(aab,aba,baa\)三个 如何求?不妨枚举.枚举是否有长度为\(k\)的最长不可重叠相同子串 可是后缀数组中并不能直接表示出子串,只能间接地用后缀来表示 长度为\(k\)的相同子串\(=>\)最大公共前缀长度为\(k\)的子串\(=>\)最大公共前缀长度大于等于

POJ 题目1743 Musical Theme(后缀数组,求一个串中最长不重叠重复子串)

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21826   Accepted: 7467 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

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

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

URAL - 1297 Palindrome(后缀数组求最长回文子串)

Description The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots Unlimited? has infiltrated into "U.S. Robotics". ?U.S. Robots? security service would have alrea

URAL 1297. Palindrome(后缀数组 求最长回文子串)

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1297 1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots