POJ 1743 Musical Theme (二分后缀数组LCP)
2016-10-20 18:09
429 查看
题意
给出一段长度小于2e4的序列,如果有两个不重叠子段的一一相邻两个数之间变化情况相同就可以说这两段的是相同的theme。小于5视为0。思路
首先我们先对序列进行处理,a[i] = a[i+1] - a[i],新序列即为变化情况的数列,问题转化成找到新序列的最长不重叠子段。二分答案x然后可以利用lcp数组的性质找到所有符合条件的最左起点和最右起点,判断和x的大小关系即可。
代码
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; #define LL long long #define Lowbit(x) ((x)&(-x)) #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1|1 #define MP(a, b) make_pair(a, b) const int INF = 0x3f3f3f3f; const int MOD = 1000000007; const int maxn = 1e5 + 10; const double eps = 1e-8; const double PI = acos(-1.0); typedef pair<int, int> pii; int n, k; int sa[maxn*2], rk[maxn*2]; int temp[maxn*2], lcp[maxn*2]; int compare_sa(int i, int j) { if (rk[i] != rk[j]) return rk[i] < rk[j]; else { int ri = i + k <= n ? rk[i+k] : -1; int rj = j + k <= n ? rk[j+k] : -1; return ri < rj; } } void construct_sa(int *s, int *sa) { for (int i = 0; i <= n; i++) { sa[i] = i; rk[i] = i < n ? s[i] : -1; } for (k = 1; k <= n; k *= 2) { sort(sa, sa + n + 1, compare_sa); temp[s[0]] = 0; for (int i = 1; i <= n; i++) temp[sa[i]] = temp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0); for (int i = 0; i <= n; i++) rk[i] = temp[i]; } } void construct_lcp(int *s, int *sa, int *lcp) { for (int i = 0; i <= n; i++) rk[sa[i]] = i; int h = 0; lcp[0] = 0; for (int i = 0; i < n; i++) { int j = sa[rk[i] - 1]; if (h > 0) h--; for (; j + h < n && i + h < n; h++) if (s[j+h] != s[i+h]) break; lcp[rk[i] - 1] = h; } } bool check(int x) { int mmin = INF, mmax = -INF; for (int i = 0; i < n; i++) if (lcp[i] >= x) { mmin = min(mmin, min(sa[i], sa[i+1])); mmax = max(mmax, max(sa[i], sa[i+1])); if (mmax - mmin > x) return true; } else { mmin = INF; mmax = -INF; } return false; } void solve() { int l = 0, r = n / 2; while (l < r) { int mid = (l + r + 1) >> 1; if (check(mid)) l = mid; else r = mid - 1; } l++; if (l < 5) l = 0; printf("%d\n", l); } int a[maxn]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while (scanf("%d", &n) && n) { for (int i = 0; i < n; i++) scanf("%d", &a[i]); n--; //原序列变形式 for (int i = 0; i < n; i++) a[i] = a[i+1] - a[i] + 100; construct_sa(a, sa); construct_lcp(a, sa, lcp); solve(); } return 0; }
相关文章推荐
- Poj 1743 Musical Theme (后缀数组+二分)
- poj 1743 Musical Theme (后缀数组+二分答案)
- POJ 1743 (后缀数组 二分) Musical Theme
- POJ 1743 Musical Theme <后缀数组+二分>
- POJ 1743 Musical Theme (后缀数组加二分求不可重叠最长重复子串)
- 【后缀数组】【二分答案】【差分】poj1743 Musical Theme
- POJ - 1743 Musical Theme 后缀数组 二分
- POJ 1743 Musical Theme (后缀数组 + 二分)
- poj 1743 Musical Theme 后缀数组
- poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- POJ-1743 Musical Theme 后缀数组
- 后缀数组 - poj1743 Musical Theme
- 【后缀数组】 POJ 1743 Musical Theme
- POJ 1743 Musical Theme 后缀数组 不可重叠最长重复子串
- POJ 1743 Musical Theme 后缀数组 楼教主男人八题之一
- 后缀数组 POJ 1743 Musical Theme
- POJ 1743 Musical Theme (后缀数组,求最长不重叠重复子串)
- poj 1743 Musical Theme 【后缀数组】
- POJ-1743 Musical Theme (后缀数组 不重叠最长重复子串)
- 【POJ】1743 Musical Theme 【后缀数组】