[洛谷P2852][USACO06DEC]牛奶模式Milk Patterns
题目大意:给一串长度为$n$的数字,求出其中最长的至少出现$k(2\leqslant k\leqslant n)$次的字段,输出长度
题解:$SAM$后$DP$
卡点:多处数组未开两倍
C++ Code:
#include <cstdio> #include <map> #define maxn 20010 int n, k, ans; inline int max(int a, int b) {return a > b ? a : b;} namespace SAM { int head[maxn << 1], cnt; struct Edge { int to, nxt; } e[maxn << 1]; void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; } int root, idx, last, p, t, np; int R[maxn << 1], fail[maxn << 1]; int sz[maxn << 1]; std::map<int, int> nxt[maxn << 1]; void init() { fail[last = idx = root = 0] = -1; } void insert(int x) { int now = ++idx; R[now] = R[p = last] + 1; sz[last = now] = 1; for (; ~p && !nxt[p][x]; p = fail[p]) nxt[p][x] = now; if (!~p) {fail[now] = root; return ;} if (R[t = nxt[p][x]] == R[p] + 1) {fail[now] = t; return ;} R[np = ++idx] = R[p] + 1; nxt[np] = nxt[t]; fail[np] = fail[t]; fail[t] = fail[now] = np; for (; ~p && nxt[p][x] == t; p = fail[p]) nxt[p][x] = np; } void dfs(int rt) { for (int i = head[rt]; i; i = e[i].nxt) { int v = e[i].to; dfs(v); sz[rt] += sz[v]; } if (sz[rt] >= k) ans = max(ans, R[rt]); } } int main() { scanf("%d%d", &n, &k); SAM::init(); for (int i = 1, x; i <= n; i++) scanf("%d", &x), SAM::insert(x); for (int i = 1; i <= SAM::idx; i++) SAM::add(SAM::fail[i], i); SAM::dfs(0); printf("%d\n", ans); return 0; }