zoukankan      html  css  js  c++  java
  • 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;
    }

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

  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4970212.html
Copyright © 2011-2022 走看看