[洛谷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;
}

 

posted @ 2018-09-10 15:33  Memory_of_winter  阅读(164)  评论(0编辑  收藏  举报