[后缀自动机][单调队列优化DP] BZOJ 2806: [Ctsc2012]Cheat
2017-12-23 18:45
549 查看
Solution
对m个串建立后缀自动机。对n个串单独考虑:
显然答案可以二分。
记pi表示这个串的i位置可以在SAM上匹配到的最长长度。
考虑DP:fi表示考虑前i个字符,最长熟悉字符串的长度。fi=max{fi−1,fj−j+i},L≤i−j≤pi分析一下有贡献的区间j∈[i−pi,i−L]。
pi有一个显然的性质pi≥pi+1−1。
考虑i和i+1:i+1−pi=i−(pi−1)≥i−pi所以单调队列维护递减的fi−i就可以O(n)DP啦。
#include <bits/stdc++.h> #define show(x) cerr << #x << " = " << x << endl using namespace std; typedef long long ll; typedef pair<int, int> Pairs; const int N = 2202020; inline char get(void) { static char buf[100000], *S = buf, *T = buf; if (S == T) { T = (S = buf) + fread(buf, 1, 100000, stdin); if (S == T) return EOF; } return *S++; } template<typename T> inline void read(T &x) { static char c; x = 0; int sgn = 0; for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1; for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0'; if (sgn) x = -x; } inline void read(char *ch) { char c; int len = 0; for (c = get(); c < '0' || c > '1'; c = get()); for (; c >= '0' && c <= '1'; c = get()) ch[len++] = c; ch[len] = 0; } int p , f ; int q ; char s ; namespace SAM { int to [4]; int mx , par ; int Tcnt, root, last; inline void Init(void) { Tcnt = root = last = 1; } inline int Extend(int c) { int p = last, np = ++Tcnt; mx[Tcnt] = mx[p] + 1; for (; p && !to[p][c]; p = par[p]) to[p][c] = np; if (p) { int q = to[p][c]; if (mx[q] != mx[p] + 1) { int nq = ++Tcnt; mx[nq] = mx[p] + 1; memcpy(to[nq], to[q], sizeof to[q]); par[nq] = par[q]; par[q] = par[np] = nq; for (; p && to[p][c] == q; p = par[p]) to[p][c] = nq; } else { par[np] = q; } } else { par[np] = root; } return last = np; } int sta , top; inline void Debug(int u = 1) { for (int i = 1; i <= top; i++) putchar(sta[i] + '0'); putchar('\n'); for (int i = 0; i < 3; i++) if (to[u][i]) { sta[++top] = i; Debug(to[u][i]); --top; } } } int n, m, len; using namespace SAM; inline bool Check(int L) { int u = root; for (int i = 1; i <= len; i++) { int c = s[i] - '0'; if (to[u][c]) { u = to[u][c]; p[i] = p[i - 1] + 1; } else { while (u && !to[u][c]) u = par[u]; if (u) { p[i] = mx[u] + 1; u = to[u][c]; } else { u = root; p[i] = 0; } } } for (int i = 0; i <= len; i++) f[i] = 0; int h = 1, t = 0; for (int i = 1; i <= len; i++) { f[i] = f[i - 1]; if (i >= L) { int res = f[i - L] - (i - L); while (h <= t && f[q[t]] - q[t] < res) --t; q[++t] = i - L; } while (h <= t && q[h] < i - p[i]) ++h; if (h <= t) f[i] = max(f[i], f[q[h]] - q[h] + i); } return f[len] * 10 >= len * 9; } int main(void) { freopen("1.in", "r", stdin); read(n); read(m); Init(); for (int i = 1; i <= m; i++) { read(s); len = strlen(s); for (int i = 0; i < len; i++) Extend(s[i] - '0'); Extend(2); } // Debug(); for (int i = 1; i <= n; i++) { read(s + 1); len = strlen(s + 1); int L = 1, R = len, Mid, Ans; while (L <= R) { Mid = (L + R) >> 1; if (Check(Mid)) L = (Ans = Mid) + 1; else R = Mid - 1; } printf("%d\n", Ans); } return 0; }
相关文章推荐
- BZOJ 2806: [Ctsc2012]Cheat 后缀自动机+单调队列优化DP
- [二分 后缀自动机 单调队列优化DP] BZOJ 2806 [Ctsc2012]Cheat
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
- [BZOJ2806][Ctsc2012]Cheat(后缀自动机+单调队列优化dp)
- BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
- bzoj 2806 [Ctsc2012]Cheat 后缀自动机 单调队列优化dp
- 【bzoj2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化dp
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
- [BZOJ2806][Ctsc2012][后缀自动机][队列优化][DP]Cheat
- bzoj 2806: [Ctsc2012]Cheat (后缀自动机+dp+单调队列)
- [BZOJ2806] [CTSC2012] Cheat - 后缀自动机 - DP - 单调队列
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
- BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】
- bzoj2806 【Ctsc2012】 Cheat 后缀自动机+单调队列优化dp
- bzoj2806 [Ctsc2012]Cheat(单调队列优化dp+二分+广义SAM)
- bzoj2806 [Ctsc2012]Cheat(后缀自动机+单调队列优化DP)
- [BZOJ2806][Ctsc2012]Cheat(广义后缀自动机+dp)
- bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP
- BZOJ 2806 (ctsc 2012) Cheat 后缀自动机预处理 + DP
- 【BZOJ2806】Cheat(后缀自动机,二分答案,动态规划,单调队列)