[BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】
题目链接:BZOJ - 3207
题目分析
先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x 。
这一步可以使用可持久化线段树来做,虽然感觉可以有更简单的做法,但是我没有什么想法...
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int MaxN = 200000 + 5, P = 233, Mod = 3371723, MaxNode = 8000000 + 5; int n, m, k, en, TL_Index, Node_Index; int A[MaxN], B[MaxN], Root[MaxN], Lc[MaxNode], Rc[MaxNode], T[MaxNode]; struct HashNode { int Pos, TL; HashNode *Next; } H[MaxN], *Ph = H, *Hash[Mod + 5]; bool Cmp(int *AA, int x, int *AB, int y) { for (int i = 0; i < k; ++i) if (AA[x + i] != AB[y + i]) return false; return true; } void Insert(int &Now, int Last, int s, int t, int x) { if (Now == 0) Now = ++Node_Index; if (s == t) { T[Now] = T[Last] + 1; return; } int m = (s + t) >> 1; if (x <= m) { Rc[Now] = Rc[Last]; Insert(Lc[Now], Lc[Last], s, m, x); } else { Lc[Now] = Lc[Last]; Insert(Rc[Now], Rc[Last], m + 1, t, x); } } int main() { scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= n; ++i) scanf("%d", &A[i]); en = n - k + 1; int HN, TL_i; HashNode *Now; TL_Index = 0; Node_Index = 0; for (int i = 1; i <= en; ++i) { HN = 0; for (int j = i; j < i + k; ++j) { HN = HN * P + A[j]; if (HN > Mod) HN %= Mod; } Now = Hash[HN]; TL_i = 0; while (Now != NULL) { if (Cmp(A, i, A, Now -> Pos)) { TL_i = Now -> TL; break; } Now = Now -> Next; } if (TL_i == 0) { ++Ph; Ph -> Pos = i; Ph -> TL = TL_i = ++TL_Index; Ph -> Next = Hash[HN]; Hash[HN] = Ph; } Insert(Root[i], Root[i - 1], 1, n, TL_i); } int l, r, s, t, mid, x, y; for (int i = 1; i <= m; ++i) { scanf("%d%d", &l, &r); for (int j = 1; j <= k; ++j) scanf("%d", &B[j]); HN = 0; for (int j = 1; j <= k; ++j) { HN = HN * P + B[j]; if (HN > Mod) HN %= Mod; } TL_i = 0; Now = Hash[HN]; while (Now != NULL) { if (Cmp(B, 1, A, Now -> Pos)) { TL_i = Now -> TL; break; } Now = Now -> Next; } if (TL_i == 0 || r - l + 1 < k) printf("Yes\n"); else { r = r - k + 1; x = Root[l - 1]; y = Root[r]; s = 1; t = n; while (s != t) { mid = (s + t) >> 1; if (TL_i <= mid) { x = Lc[x]; y = Lc[y]; t = mid; } else { x = Rc[x]; y = Rc[y]; s = mid + 1; } } if (T[y] - T[x] > 0) printf("No\n"); else printf("Yes\n"); } } return 0; }