Musical Theme POJ - 1743(后缀数组+二分)
求不可重叠最长重复子串
对于height[i]定义为sa[i]和 sa[i-1]的最长公共前缀
这个最长公共前缀的值肯定是最大的
证明:
设rank[j] < rank[k], 则不难证明后缀j和k的LCP的长度等于height[rank[j]+1], height[rank[j]+2],```, height[rank[k]]中的最小值
所以设后缀j和后缀k的最长公共前缀为h
则h <= height[i] i为( rank[j], rank[k] ]
即可用于解决 不可重叠最长重复子串
二分枚举长度k
然后遍历height
因为height[i] 即为最大 所以只要在height[i] >= k 时判断sa[i] 和 sa[i-1] 的差值是否大于k即可(即能保证不重叠)
还有这题对于数据有些处理
“可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值”
我们把输入的值用后一项 - 前一项 得到新的数组 只不过k值由最小长度5 变成了4
例 4 5 6 10 11 12
新数组 1 1 4 1 1
即使子串被加上或减去同一个整数值
但它们之间的差值还是一样的
emm///不要忘了处理n == 1 的时候。。。。re了n发。。。真是的 过分呢。。。
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <cctype> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <cmath> #define rap(i, a, n) for(int i=a; i<=n; i++) #define rep(i, a, n) for(int i=a; i<n; i++) #define lap(i, a, n) for(int i=n; i>=a; i--) #define lep(i, a, n) for(int i=n; i>a; i--) #define rd(a) scanf("%d", &a) #define rlld(a) scanf("%lld", &a) #define rc(a) scanf("%c", &a) #define rs(a) scanf("%s", a) #define MOD 2018 #define LL long long #define ULL unsigned long long #define Pair pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define _ ios_base::sync_with_stdio(0),cin.tie(0) //freopen("1.txt", "r", stdin); using namespace std; const int maxn = 100010, INF = 0x7fffffff; int a[maxn], s[maxn]; int sa[maxn], t[maxn], t2[maxn], c[maxn], n; int ran[maxn], height[maxn]; void get_sa(int m) { int i, *x = t, *y = t2; for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[i] = s[i]]++; for(i = 1; i < m; i++) c[i] += c[i-1]; for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; for(int k = 1; k <= n; k <<= 1) { int p = 0; for(i = n-k; i < n; i++) y[p++] = i; for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k; for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[y[i]]]++; for(i = 0; i< m; i++) c[i] += c[i-1]; for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y); p = 1; x[sa[0]] = 0; for(i = 1; i < n; i++) x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k] ? p-1 : p++; if(p >= n) break; m = p; } int k = 0; for(i = 0; i < n; i++) ran[sa[i]] = i; for(i = 0; i < n; i++) { if(k) k--; int j = sa[ran[i]-1]; while(s[i+k] == s[j+k]) k++; height[ran[i]] = k; } } bool solve(int k) { int minn = INF, maxx = -INF; rep(i, 1, n) { if(height[i] >= k) { minn = min(minn, min(sa[i], sa[i-1])); maxx = max(maxx, max(sa[i], sa[i-1])); if(maxx - minn >= k) return true; } else minn = INF, maxx = -INF; } return false; } int main() { while(~rd(n) && n) { rep(i, 0, n) rd(a[i]); if(n == 1) { puts("0"); continue; } rep(i, 0, n-1) s[i] = a[i+1] - a[i] + 100; s[n-1] = 0; get_sa(200); int l = 0, r = n; while(l <= r) { int mid = l + (r - l) / 2; if(solve(mid)) l = mid + 1; else r = mid - 1; } if(l >= 4) cout<< r+1 <<endl; else cout<< "0" <<endl; } return 0; }
自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。