您的位置:首页 > 其它

POJ 1743 Musical Theme

2012-03-09 22:24 204 查看
题目大意:

给出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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: