题意:
n个数,选取一段子序列,满足以下条件:
1.长度至少为5
2.在数列中其他位置出现过(允许转置)
3.与其他位置出现的不重叠
转置:将恒定的正或负值添加到子序列上
例如:
n个数为1,2,3,4,5,6,7,8,9,10
12345是一段子序列,那6,7,8,9,10也是,因为前者加5等于后者,且两者没有重叠
题解:
人是傻的,完全不会。。。
虽然两段序列不相等,但是也是有关系的,他们的差分区间相同,也就是其两两之间的差值一样,这样题目就转化成不重叠的最长公共子串问题
可以用二分+后缀数组
我们将原数组前后相减得到的新数据做后缀数组
二分的check:
二分最大长度k
检查两个子串是否不想交且公共前缀>=k
顺序扫描height数组
(height反应的是相邻两个后缀的lcp长度)
把height>=k的放在一起统计(将公共前缀>=k满足条件的串放在一起),这是为了实现公共前缀>=k
保证其中最大的sa - 最小的sa > k,说明两个子串的位置距离差大于k,这是为了保证不相交
(SA[i]排序第i的后缀的开始位置)
例如字符串=“aabaaaab'”
当k=2时,后缀分为四组
最长公共前缀不小于k 的两个后缀一定在同一组
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxm = 100005; const int INF = 1e9 + 7; int a[maxm], b[maxm], sa[maxm], s[maxm], Rank[maxm], id[maxm], Height[maxm]; int n, m; void Rsort() { for (int i = 0; i <= m; i++) s[i] = 0; for (int i = 1; i <= n; i++) s[Rank[id[i]]] ++; for (int i = 1; i <= m; i++) s[i] += s[i - 1]; for (int i = n; i >= 1; i--) sa[s[Rank[id[i]]] --] = id[i]; } int cmp(int *f, int x, int y, int w) { return f[x] == f[y] && f[x + w] == f[y + w]; } void suffix() { for (int i = 1; i <= n; i++) Rank[i] = a[i], id[i] = i; m = 200, Rsort(); for (int w = 1, p = 1, i; p < n; w += w, m = p) { for (p = 0, i = n - w + 1; i <= n; i++) id[++p] = i; for (i = 1; i <= n; i++) if (sa[i] > w) id[++p] = sa[i] - w; Rsort(), swap(Rank, id), Rank[sa[1]] = p = 1; for (i = 2; i <= n; i++) Rank[sa[i]] = cmp(id, sa[i], sa[i - 1], w) ? p : ++p; } int j, k = 0; for (int i = 1; i <= n; Height[Rank[i++]] = k) for (k = k ? k - 1 : k, j = sa[Rank[i] - 1]; a[i + k] == a[j + k]; k++); } int judge(int x) { int mi = INF, mx = -INF; for (int i = 2;i <= n;i++) { if (Height[i] >= x) { mi = min(mi, min(sa[i], sa[i - 1])); mx = max(mx, max(sa[i], sa[i - 1])); if (mx - mi > x) return 1; } else mi = INF, mx = -INF; } return 0; } int main() { int i, j, k, sum, ans; while (scanf("%d", &n), n != 0) { ans = 0; for (i = 1;i <= n;i++) scanf("%d", &b[i]); for (i = 1;i <= n;i++) a[i] = b[i] - b[i - 1] + 100; suffix(); int l = 0, r = n * 2; while (r - l > 1) { int mid = (r + l) / 2; if (judge(mid)) l = mid, ans = mid; else r = mid; } if (ans >= 4) printf("%d\n", ans + 1); else printf("0\n"); } return 0; }