POJ 1743 Musical Theme
2012-03-09 22:24
197 查看
题目大意:
给出N个数, 相邻两数做差之后, 得到N - 1个数, 求一个最大的M, 使得存在两个长为M的子串完全相同, 且两个字串不能有重叠的部分(其实还要再错开一位).
简要分析:
记得在USACO中做过这道题. 标准做法当然是后缀数组, 但我用哈希做的.
明显答案可以二分, 二分答案M之后, 从左到右维护长为M的子串的哈希值, 并记录某个哈希值最早出现的下标位置, 这个可以用map搞. 于是就完了. 时间复杂度O(NlogN). 哈希值的算法就很多了, 只需满足一个需求, 就是在已有1..M这个子串的哈希的情况下, 能O(1)得到2..M+1的哈希值. 我用的是大质数幂取模法, 因为C语言的unsigned long long乘爆之后自动对上界取模了, 于是世界就和谐了.
PS: 用STL的map还要TLE, 于是手写hash_map, 详见代码.
代码实现:
View Code
给出N个数, 相邻两数做差之后, 得到N - 1个数, 求一个最大的M, 使得存在两个长为M的子串完全相同, 且两个字串不能有重叠的部分(其实还要再错开一位).
简要分析:
记得在USACO中做过这道题. 标准做法当然是后缀数组, 但我用哈希做的.
明显答案可以二分, 二分答案M之后, 从左到右维护长为M的子串的哈希值, 并记录某个哈希值最早出现的下标位置, 这个可以用map搞. 于是就完了. 时间复杂度O(NlogN). 哈希值的算法就很多了, 只需满足一个需求, 就是在已有1..M这个子串的哈希的情况下, 能O(1)得到2..M+1的哈希值. 我用的是大质数幂取模法, 因为C语言的unsigned long long乘爆之后自动对上界取模了, 于是世界就和谐了.
PS: 用STL的map还要TLE, 于是手写hash_map, 详见代码.
代码实现:
View Code
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; typedef unsigned long long hash_t; const int MAX_N = 20000, SEED = 99991; int n, a[MAX_N]; hash_t b[MAX_N - 1], mypow[MAX_N]; struct hash_map_t { static const int MOD = 196613; int cnt, begin[MOD], val[MAX_N * 2], next[MAX_N * 2]; hash_t end[MAX_N * 2]; void clear() { cnt = 0, memset(begin, -1, sizeof(begin)); } hash_map_t() { cnt = 0, memset(begin, -1, sizeof(begin)); } void push(hash_t x, int p) { int s = x % MOD; next[cnt] = begin[s]; begin[s] = cnt; end[cnt] = x; val[cnt ++] = p; } int ask(hash_t x) { int s = x % MOD; for (int now = begin[s]; now != -1; now = next[now]) if (end[now] == x) return val[now]; return -1; } } hash; bool check(int x) { if (x < 5) return 0; int len = x - 1; hash_t t = 0ULL; for (int i = 0; i < len; i ++) t = t * SEED + b[i]; hash.clear(); hash.push(t, 0); for (int i = 1; i < n - len + 1; i ++) { t -= b[i - 1] * mypow[len - 1]; t = t * SEED + b[i + len - 1]; int p = hash.ask(t); if (p < 0) hash.push(t, i); else { p += len; if (i > p) return 1; } } return 0; } int main() { mypow[0] = 1ULL; for (int i = 1; i < MAX_N; i ++) mypow[i] = mypow[i - 1] * SEED; while (scanf("%d", &n) != EOF && n) { for (int i = 0; i < n; i ++) scanf("%d", &a[i]); for (int i = 0; i < n - 1; i ++) b[i] = a[i + 1] - a[i]; int lb = 5, rb = n + 1; n --; while (lb + 1 < rb) { int mid = (lb + rb) >> 1; if (check(mid)) lb = mid; else rb = mid; } if (!check(lb)) printf("0\n"); else printf("%d\n", lb); } return 0; }
相关文章推荐
- 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
- Musical Theme - poj 1743(求最大不重叠重复子串)
- [后缀数组+二分] 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
- POJ 1743 Musical Theme ——后缀数组
- POJ 1743 Musical Theme (后缀数组加二分求不可重叠最长重复子串)
- poj 1743 Musical Theme 后缀数组