• SPOJ8222 Substrings( 后缀自动机 + dp )


    题目大意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。F(1)..F(Length(S)) 

    建出SAM, 然后求出Right, 求Right可以按拓扑序dp..Right就是某个点到结束状态的路径数, parent树上last的那一条链都是结束状态...然后用Right去更新答案..

    spoj卡常数..一开始用DFS就炸了, 改用BFS就A了..

    (贴一下丽洁姐的题解: 我们构造S的SAM,那么对于一个节点s,它的长度范围是 [Min(s),Max(s)],同时他的出现次数是|Right(s)|。那么我们用|Right(s)|去更新F(Max(s))的值。 同时最后从大到小依次用F(i)去更新F(i-1)即可。)

    -----------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
     
    using namespace std;
     
    const int cn = 26;
    const int maxn = 1000009;
     
    bool vis[maxn];
    int Right[maxn], ans[maxn], deg[maxn], n = 0, N;
    char s[maxn];
     
    struct Node {
    Node *ch[cn], *fa;
    int len, id;
    } pool[maxn], *pt, *root, *last;
     
    Node* newNode(int v) {
    memset(pt->ch, 0, sizeof pt->ch);
    pt->fa = 0;
    pt->len = v;
    pt->id = n++;
    return pt++;
    }
     
    void SAM_init() {
    pt = pool;
    root = last = newNode(0);
    }
     
    void Extend(int c) {
    Node *p = last, *np = newNode(p->len + 1);
    for(; p && !p->ch[c]; p = p->fa)
    p->ch[c] = np;
    if(!p)
    np->fa = root;
    else {
    Node* q = p->ch[c];
    if(p->len + 1 == q->len)
    np->fa = q;
    else {
    Node* nq = newNode(p->len + 1);
    memcpy(nq->ch, q->ch, sizeof q->ch);
    nq->fa = q->fa;
    q->fa = np->fa = nq;
    for(; p && p->ch[c] == q; p = p->fa)
    p->ch[c] = nq;
    }
    }
    last = np;
    }
     
    struct edge {
    int to;
    edge* next;
    } E[maxn], *Pt = E, *head[maxn];
     
    void AddEdge(int u, int v) {
    deg[Pt->to = v]++; Pt->next = head[u]; head[u] = Pt++;
    }
     
    void SAM_build() {
    scanf("%s", s);
    N = strlen(s);
    for(int i = 0; i < N; i++)
    Extend(s[i] - 'a');
    }
     
    queue<Node*> q;
    queue<int> Q;
     
    void ADDEDGE() {
    memset(deg, 0, sizeof deg);
    memset(vis, 0, sizeof vis);
    q.push(root);
    vis[root->id] = true;
    while(!q.empty()) {
    Node* t = q.front(); q.pop();
    for(int i = 0; i < cn; i++) if(t->ch[i]) {
    AddEdge(t->ch[i]->id, t->id);
    if(!vis[t->ch[i]->id]) {
    q.push(t->ch[i]);
    vis[t->ch[i]->id] = true;
    }
    }
    }
    }
     
    void getRight() {
    memset(Right, 0, sizeof Right);
    for(Node* t = last; t; t = t->fa)
    Right[t->id] = 1;
    Q.push(last->id);
    while(!Q.empty()) {
    int x = Q.front(); Q.pop();
    for(edge* e = head[x]; e; e = e->next) {
    Right[e->to] += Right[x];
    if(!--deg[e->to])
    Q.push(e->to);
    }
    }
    }
     
    void update() {
    memset(vis, 0, sizeof vis);
    q.push(root);
    vis[root->id] = true;
    while(!q.empty()) {
    Node* t = q.front(); q.pop();
    ans[t->len] = max(ans[t->len], Right[t->id]);
    for(int i = 0; i < cn; i++) if(t->ch[i] && !vis[t->ch[i]->id]) {
    q.push(t->ch[i]);
    vis[t->ch[i]->id] = true;
    }
    }
    }
     
    void solve() {
    getRight();
    update();
    for(int i = N; --i; )
    ans[i] = max(ans[i], ans[i + 1]);
    for(int i = 1; i <= N; i++)
    printf("%d ", ans[i]);
    }
     
    int main() {
    SAM_init();
    SAM_build();
    ADDEDGE();
    solve();
    return 0;
    }

    ----------------------------------------------------------------------------- 

  • 相关阅读:
    2020年终将过去
    Opus从入门到精通(一):简介
    0907 RTCP FB
    ClickHouse源码笔记6:探究列式存储系统的排序
    C++雾中风景17:模板的非推断语境与std::type_identity
    ClickHouse源码笔记5:聚合函数的源码再梳理
    ClickHouse源码笔记4:FilterBlockInputStream, 探寻where,having的实现
    ClickHouse源码笔记3:函数调用的向量化实现
    Doris开发手记1:解决蛋疼的MySQL 8.0连接问题
    声音克隆_论文翻译:2019_Transfer Learning from Speaker Verification to Multispeaker Text-To-Speech Synthesis
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4970212.html
Copyright © 2020-2023  润新知