[POJ1743]Musical Theme[SA+二分]

2009那篇论文里介绍的做法

这里面有下载链接

这个题是要转成差分序列再做的

导致我WA了一发的地方 if (Max - Min > x) return 1; 写成>=了(论文里说的距离不小于k 转成差分序列好像就要写成>)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace std;
int k, n, rnk[20005], sa[20005], s[20005], H[20005], c[20005];

void Sort(int *x, int *y, int *rk) {
  static int C[20005];
  for (int i = 0; i <= k; ++i) C[i] = 0;
  for (int i = 1; i <= n; ++i) ++C[rk[i]];
  for (int i = 1; i <= k; ++i) C[i] += C[i - 1];
  for (int i = n; i; --i) y[C[rk[x[i]]]--] = x[i];
}
inline bool cmp(int *y, int a, int b, int m) {return y[a] == y[b] && y[a + m] == y[b + m];}
void get_SA() {
  static int Y[20005];
  int *y = Y, *rk = rnk;
  k = 200;
  for (int i = 1; i <= n; ++i) rk[i] = s[y[i] = i];
  Sort(y, sa, rk);
  for (int m = 1, p = 0; p < n; k = p, m <<= 1) {
    for (p = 0; p < m; ++p) y[p + 1] = n - m + p + 1;
    for (int i = 1; i <= n; ++i)
      if (sa[i] > m) y[++p] = sa[i] - m;
    Sort(y, sa, rk), swap(y, rk);
    rk[sa[p = 1]] = 1;
    for (int i = 2; i <= n; ++i) rk[sa[i]] = cmp(y, sa[i - 1], sa[i], m) ? p : ++p;
  }
  for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
}

void get_H() {
  for (int i = 1, k = 0; i <= n; H[rnk[i++]] = k)
    for (k ? --k : 0; s[i + k] == s[sa[rnk[i] - 1] + k]; ++k);
}

bool check(int x) {
  for (int i = 2, Min = sa[1], Max = sa[1]; i <= n; ++i) {
    if (H[i] >= x) Min = min(Min, sa[i]), Max = max(Max, sa[i]);
    else Max = Min = sa[i];
    if (Max - Min > x) return 1;
  }
  return 0;
}

int main() {
  while (~scanf("%d", &n) && n) {
    for (int i = 1; i <= n; ++i) scanf("%d", c + i), s[i] = c[i] - c[i - 1] + 90;
    get_SA();
    get_H();
    int l = 1, r = n, mid;
    while (l <= r) {
      if (check(mid = l + r >> 1)) l = mid + 1;
      else r = mid - 1;
    }
    cout << (l < 5 ? 0 : l) << endl;//l-1<4?0:l-1+1
  }
  return 0;
}

原文地址:https://www.cnblogs.com/storz/p/10604271.html

时间: 2025-01-17 01:24:08

[POJ1743]Musical Theme[SA+二分]的相关文章

poj1743 Musical Theme

地址:http://poj.org/problem?id=1743 题目: Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 28675   Accepted: 9674 Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range

POJ1743 Musical Theme [没做出来]

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 27539   Accepted: 9290 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 Musical Theme(最长不可重叠子串,后缀数组+二分)

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 musical timing; b

【后缀数组】【二分答案】【差分】poj1743 Musical Theme

差分消除加减一个值得影响,貌似r二分上界要设成(n-2)/2?为啥? sa求不可重叠最长重复子串 给定一个字符串,求最长重复子串,这两个子串不能重叠.算法分析:这题比上一题稍复杂一点.先二分答案,把题目变成判定性问题:判断是否存在两个长度为 k 的子串是相同的,且不重叠.解决这个问题的关键还是利用height 数组.把排序后的后缀分成若干组,其中每组的后缀之间的 height 值都不小于 k. 容易看出,有希望成为最长公共前缀不小于 k 的两个后缀一定在同一组. 然后对于每组后缀,只须判断每个后

[POJ1743] Musical Theme (后缀数组)

题目概述: 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 musical tim

[poj1743]Musical Theme后缀数组

题意:不可重叠最长重复子串 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题.“主题”是整个音符序列的一个子串,它需要满足如下条件: 1.长度至少为5个音符. 2.在乐曲中重复出现.(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值) 3.重复出现的同一主题不能有公共部分. 二分答案,转化为存在性判定,后缀数组问题的套路解法 1 #include <cstdlib> 2 #incl

POJ 1743 Musical Theme Hash + 二分

原本是<后缀数组——处理字符串的有力工具>论文中的第一道例题,发现自己智商不够,一个下午没有看懂后缀数组= =,就用hash写了 #include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; typedef long long LL; const int maxn = 20000 + 5; const int mod =

POJ 1743 Musical Theme【SAM】

POJ1743 Musical Theme 要找长度\(\ge 5\)且出现次数\(\ge 2\)并且第一次出现和最后一次出现不重叠的最长子串. 题目条件中,如果对于两个串,在一个串的每个数上都加上相同的数之后可以得到另一个串,那么这个两个串可以被是相同的. 首先我们先得到差分数组,然后要求的就是差分数组中长度\(\ge 4\)且出现次数\(\ge 2\)并且第一次出现和最后一次出现不重叠的最长子串 我们需要知道的是每个等价类中终点的最左端和最右端的位置,即(\(firstpos,lastpos

Poj 1743 Musical Theme (后缀数组+二分)

题目链接: Poj  1743 Musical Theme 题目描述: 给出一串数字(数字区间在[1,88]),要在这串数字中找出一个主题,满足: 1:主题长度大于等于5. 2:主题在文本串中重复出现(或者经过调转出现,调转是主题同时加上或者减去同一个整数) 3:重复主题不能重叠 解题思路: 求调转重复出现的子串,那么主题之间的差值一定是不变的.可以求文本串s中相邻两个数的差值,重新组成一个新的文本串S,然后找S后缀串中最长公共不重叠前缀.rank相邻的后缀串,公共前缀一定最长,但是有可能重叠.