POJ 3693 Maximum repetition substring
2012-03-10 20:05
363 查看
题目大意:
一个字符串的重复数x的含义是, 它可以由至多x个相同的字符串连接而成. 现在给出一个长度为N的字符串, N不超过100000, 求出它的重复数最大且字典序最小的子串.
简要分析:
论文题, 思路很有意思. 我们定义重复的字符串为循环节, 那么我们就枚举循环节长度L, 那么如果答案存在, 则必定包含s[0], s[L], s[2 * L]等中相邻的连个. 我们再枚举j, 则相当于我们假定s[j * L]和s[(j + 1) * L]在答案中, 且s[j * L]在第一个循环节内. 这里我们需要求后缀j * L和后缀(j + 1) * L的最长公共前缀, 这个可以用后缀数组和ST算法做好预处理后O(1)回答. 设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀, 看是否不小于L. 对于字典序的保证, 我的算法没有保证复杂度, 因为我是从每个j * L位置暴力往前for答案的初始位置, 答案的比较用后缀数组就好, 中间加上各种剪枝跑得还凑合. 在忽略那个暴力的情况下, 算法复杂度为O(N * (1 / 1 + 1 / 2 + ... + 1 / N)) = O(NlogN).
代码实现:
View Code
一个字符串的重复数x的含义是, 它可以由至多x个相同的字符串连接而成. 现在给出一个长度为N的字符串, N不超过100000, 求出它的重复数最大且字典序最小的子串.
简要分析:
论文题, 思路很有意思. 我们定义重复的字符串为循环节, 那么我们就枚举循环节长度L, 那么如果答案存在, 则必定包含s[0], s[L], s[2 * L]等中相邻的连个. 我们再枚举j, 则相当于我们假定s[j * L]和s[(j + 1) * L]在答案中, 且s[j * L]在第一个循环节内. 这里我们需要求后缀j * L和后缀(j + 1) * L的最长公共前缀, 这个可以用后缀数组和ST算法做好预处理后O(1)回答. 设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀, 看是否不小于L. 对于字典序的保证, 我的算法没有保证复杂度, 因为我是从每个j * L位置暴力往前for答案的初始位置, 答案的比较用后缀数组就好, 中间加上各种剪枝跑得还凑合. 在忽略那个暴力的情况下, 算法复杂度为O(N * (1 / 1 + 1 / 2 + ... + 1 / N)) = O(NlogN).
代码实现:
View Code
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 100000; char s[MAX_N + 2]; int cas, n, sa[MAX_N + 1], rank[MAX_N + 1], cnt[MAX_N + 1], height[MAX_N + 1]; int dp[17][MAX_N + 1], log2[MAX_N + 1]; struct node_t { int v[2], p; bool operator == (const node_t &t) const { return v[0] == t.v[0] && v[1] == t.v[1]; } } nd[MAX_N + 1], tp[MAX_N + 1]; struct ans_t { int rep, start, len; bool operator < (const ans_t &t) const { if (rep != t.rep) return rep < t.rep; if (rank[start] != rank[t.start]) return rank[start] > rank[t.start]; return len > t.len; } } ans, tmp; void ra(int b) { for (int i = 1; i >= 0; i --) { memset(cnt, 0, sizeof(int) * (b + 1)); for (int j = 1; j <= n; j ++) cnt[nd[j].v[i]] ++; for (int j = 1; j <= b; j ++) cnt[j] += cnt[j - 1]; for (int j = n; j >= 1; j --) tp[cnt[nd[j].v[i]] --] = nd[j]; memcpy(nd, tp, sizeof(node_t) * (n + 1)); } for (int i = 1, j = 1, k = 1; i <= n; i = j, k ++) while (j <= n && nd[j] == nd[i]) rank[nd[j ++].p] = k; } void rmq_init() { memset(dp, 0x3f, sizeof(dp)); for (int i = 1; i <= n; i ++) dp[0][i] = height[i]; for (int i = 1; (1 << i) < n; i ++) { for (int j = 1; j <= n; j ++) { dp[i][j] = dp[i - 1][j]; if (j + (1 << (i - 1)) <= n) dp[i][j] = min(dp[i][j], dp[i - 1][j + (1 << (i - 1))]); } } } int rmq_ask(int l, int r) { if (l > r) swap(l, r); int st = log2[r - l + 1]; return min(dp[st][l], dp[st][r - (1 << st) + 1]); } int query(int l, int r) { l = rank[l], r = rank[r]; if (l > r) swap(l, r); return rmq_ask(++ l, r); } void solve() { n = strlen(s + 1); for (int i = 1; i <= n; i ++) { nd[i].v[0] = s[i]; nd[i].v[1] = 0; nd[i].p = i; } ra(255); for (int j = 1; j < n; j <<= 1) { for (int i = 1; i <= n; i ++) { nd[i].v[0] = rank[i]; nd[i].v[1] = i + j <= n ? rank[i + j] : 0; nd[i].p = i; } ra(n); } for (int i = 1; i <= n; i ++) sa[rank[i]] = i; for (int i = 1, j, k = 0; i <= n; height[rank[i ++]] = k) for (k ? k -- : 0, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; k ++); rmq_init(); ans.rep = 1; ans.start = 1; ans.len = 1; for (int i = 2; i <= n; i ++) if (s[i] < s[ans.start]) ans.start = i; for (int i = 1; i < n; i ++) for (int j = 1; j + i <= n; j += i) { int t = query(j, j + i); if (t < i) continue; int k = j - (i - t % i); t = t / i + 1; if (t + 1 < ans.rep) continue; if (t + 1 == ans.rep && (k < 1 || query(k, k + i) < i)) continue; int p = (t + 1 == ans.rep ? k : j); for ( ; p != j - i && p >= 1; p --) { t = query(p, p + i); t = t / i + 1; if (t < ans.rep) break; tmp.rep = t; tmp.start = p; tmp.len = i; if (ans < tmp) ans = tmp; } } for (int i = 0; i < ans.len * ans.rep; i ++) printf("%c", s[ans.start + i]); printf("\n"); } int main() { log2[1] = 0; for (int i = 2; i <= MAX_N; i ++) { if ((i & (i - 1)) == 0) log2[i] = log2[i - 1] + 1; else log2[i] = log2[i - 1]; } while (scanf("%s", s + 1) && s[1] != '#') { printf("Case %d: ", ++ cas); solve(); } return 0; }
相关文章推荐
- [后缀数组+枚举] hdu 2459 && poj 3693 Maximum repetition substring
- poj 3693 Maximum repetition substring (后缀数组)
- 后缀数组 POJ 3693 && hdu 2459 Maximum repetition substring
- POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)
- POJ 3693 - Maximum repetition substring (后缀数组)
- POJ 3693 Maximum repetition substring (后缀数组)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ)
- POJ 3693 Maximum repetition substring(后缀数组+ST表)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ 求重复最多的连续子串)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ 求重复最多的连续子串)
- POJ 3693 Maximum repetition substring
- 【后缀数组】【poj 3693】Maximum repetition substring
- POJ3693 Maximum repetition substring
- POJ 3693 Maximum repetition substring(连续重复子串)
- 「POJ 3693」Maximum repetition substring
- POJ 3693 Maximum repetition substring 后缀数组与区间最值的完美结合
- POJ - 3693 Maximum repetition substring 后缀数组+RMQ
- POJ 3693 Maximum repetition substring
- 【后缀数组】 HDOJ 2459 && POJ 3693 Maximum repetition substring
- poj 3693 Maximum repetition substring(08合肥 RMQ+后缀数组)