POJ-1743 Musical Theme 哈希
该题题意是给定一个音乐串,要求最长的主题串满足
可以找到两个这样的串,在对方的每一位添加一个数字
两个串互相不能够有重叠
有是多项式插值取模的hash的应用
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #define T 99991 #define MAXN 20000 #define MOD 3001 using namespace std; typedef unsigned long long UInt64; struct Node { UInt64 key; int begin, end, next; }e[3000000]; int N, seq[MAXN+5], diff[MAXN+5], head[MOD], idx; UInt64 POW[(MAXN>>1)+5]; void getint(int &t) { char c; while (c = getchar(), c < '0' || c > '9'); t = c - '0'; while (c = getchar(), c >= '0' && c <= '9') { t = t * 10 + c - '0'; } } int Hash(UInt64 key, int begin, int end) { // 这里应用贪心思想,如果前面有一个提前完成的主题,一定取前面的主题 int Rkey = key % MOD, flag = 0; for (int i = head[Rkey]; i != -1; i = e[i].next) { if (key == e[i].key) { flag = 1; if (begin > e[i].end) { return true; } } } if (!flag) { ++idx; e[idx].key = key, e[idx].begin = begin; e[idx].end = end, e[idx].next = head[Rkey]; head[Rkey] = idx; } return false; } bool Accept(int k) { UInt64 key = 0; idx = -1; memset(head, 0xff, sizeof (head)); for (int i = 1; i <= k; ++i) { key = key * T + diff[i]; } if (Hash(key, 0, k)) { return true; } for (int i = 2; i <= N-k+1; ++i) { key -= diff[i-1] * POW[k-1]; key = key * T + diff[i+k-1]; if (Hash(key, i-1, i+k-1)) { // 这里的begin和end要映射到原数组中 return true; } } return false; } int bsearch(int l, int r) { int mid; while (l <= r) { mid = (l+r) >> 1; if (Accept(mid)) { l = mid + 1; } else { r = mid - 1; } } return r; } int main() { POW[0] = 1; int ans; for (int i = 1; i <= 10000; ++i) { POW[i] = POW[i-1] * T; } while (scanf("%d", &N), N) { for (int i = 0; i < N; ++i) { getint(seq[i]); // scanf("%d", &seq[i]); } N -= 1; for (int i = 1; i <= N; ++i) { diff[i] = seq[i] - seq[i-1] + 203; } if (N >= 9) { ans = bsearch(4, N>>1); if (ans >= 4) { printf("%d\n", ans+1); } else { puts("0"); } } else { puts("0"); } } return 0; }