zoukankan      html  css  js  c++  java
  • 模板

    https://www.luogu.org/problem/P3804
    求子串的出现次数。用类似拓扑排序的思想,从没有出度的节点开始把他的cnt加在他的后缀连接上。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    struct Node {
        int len, link, ch[26];
        //额外信息
        int cnt, head;
        void NewNode(int l = 0) {
            len = l, memset(ch, 0, sizeof(ch)), link = 0;
            cnt = 1, head = 0;
        }
        void CopyNewNode(const int &l, const Node& n) {
            len = l, memcpy(ch, n.ch, sizeof(ch)), link = n.link;
            cnt = 0, head = 0;
        }
    };
    
    const int MAXN = 1000000;
    
    struct Edge {
        int to, next;
    } edge[(MAXN << 1) + 5];
    int etop;
    
    //SuffixAutomaton
    struct SAM {
        Node nd[(MAXN << 1) + 5];
        int top, last;  //top为节点个数,last末尾节点的位置
    
        void init() {
            nd[1].NewNode();
            top = 1, last = 1;
        }
    
        void extend(char ch) {
            int c = ch - 'a';
            int p = last, x = last = ++top;
            nd[x].NewNode(nd[p].len + 1);
            for(; p && !nd[p].ch[c]; p = nd[p].link)
                nd[p].ch[c] = x;
            if(!p)
                nd[x].link = 1;
            else {
                int q = nd[p].ch[c];
                if(nd[p].len + 1 == nd[q].len)
                    nd[x].link = q;
                else {
                    int y = ++top;
                    nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
                    nd[q].link = nd[x].link = y;
                    for(; p && nd[p].ch[c] == q; p = nd[p].link)
                        nd[p].ch[c] = y;
                }
            }
        }
    
        void dfs(int id) {
            for(int i = nd[id].head; i; i = edge[i].next) {
                dfs(edge[i].to);
                nd[id].cnt += nd[edge[i].to].cnt;
            }
        }
    
        ll solve() {
            //计算每一种子串的数量
            etop = 0;
            for(int i = top; i >= 2; --i) {
                ++etop;
                edge[etop].to = i;
                edge[etop].next = nd[nd[i].link].head;
                nd[nd[i].link].head = etop;
            }
            dfs(1);
            ll res = 0;
            for(int i = top; i >= 2; --i)
                if(nd[i].cnt > 1) {
                    ll tmp = 1ll * nd[i].cnt * nd[i].len;
                    if(tmp > res)
                        res = tmp;
                }
            return res;
        }
    } sam;
    
    char s[MAXN + 5];
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        scanf("%s", s);
        sam.init();
        for(int i = 0; s[i] != ''; ++i)
            sam.extend(s[i]);
        printf("%lld
    ", sam.solve());
    }
    

    这个link树不如回文机优美,但是可以用拓扑排序来非递归求。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    struct Node {
        int len, link, ch[26];
        //额外信息
        int cnt;
        void NewNode(int l = 0) {
            len = l, memset(ch, 0, sizeof(ch)), link = 0;
            cnt = 1;
        }
        void CopyNewNode(const int &l, const Node& n) {
            len = l, memcpy(ch, n.ch, sizeof(ch)), link = n.link;
            cnt = 0;
        }
    };
    
    const int MAXN = 1000000;
    
    //SuffixAutomaton
    struct SAM {
        Node nd[(MAXN << 1) + 5];
        int top, last;  //top为节点个数,last末尾节点的位置
    
        void init() {
            nd[1].NewNode();
            top = 1, last = 1;
        }
    
        void extend(char ch) {
            int c = ch - 'a';
            int p = last, x = last = ++top;
            nd[x].NewNode(nd[p].len + 1);
            for(; p && !nd[p].ch[c]; p = nd[p].link)
                nd[p].ch[c] = x;
            if(!p)
                nd[x].link = 1;
            else {
                int q = nd[p].ch[c];
                if(nd[p].len + 1 == nd[q].len)
                    nd[x].link = q;
                else {
                    int y = ++top;
                    nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
                    nd[q].link = nd[x].link = y;
                    for(; p && nd[p].ch[c] == q; p = nd[p].link)
                        nd[p].ch[c] = y;
                }
            }
        }
    
        int d[(MAXN << 1) + 5];
        int que[(MAXN << 1) + 5], front, back;
    
        ll solve() {
            //计算每一种子串的数量
            memset(d, 0, sizeof(d));
            front = 1, back = 0;
            for(int i = top; i >= 2; --i)
                ++d[nd[i].link];
            for(int i = top; i >= 2; --i)
                if(!d[i])
                    que[++back] = i;
            while(back >= front) {
                int u = que[front], v = nd[que[front]].link;
                nd[v].cnt += nd[u].cnt;
                --d[v];
                if(!d[v])
                    que[++back] = v;
                ++front;
            }
            ll res = 0;
            for(int i = top; i >= 2; --i)
                if(nd[i].cnt > 1) {
                    ll tmp = 1ll * nd[i].cnt * nd[i].len;
                    if(tmp > res)
                        res = tmp;
                }
            return res;
        }
    } sam;
    
    char s[MAXN + 5];
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        scanf("%s", s);
        sam.init();
        for(int i = 0; s[i] != ''; ++i)
            sam.extend(s[i]);
        printf("%lld
    ", sam.solve());
    }
    

    https://vjudge.net/contest/31226#problem/A
    两个字符串ST的最长公共子串,对S构造SAM。然后逐个比较T的前缀。其实是逐个加入T的字符c,每次都尝试往后走到c,成功则len+1,否则退后到他的后缀连接上,同时更新len,直到没有办法继续后缀连接则这个字符彻底失配。比dp解法快多了。

    记得要偏移’a'就都偏移'a',别演戏。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    struct Node {
        int len, link;
        int ch[26];
        //额外信息
        //int cnt;
        void NewNode(int l = 0) {
            len = l, link = 0;
            memset(ch, 0, sizeof(ch));
            //cnt = 1;
        }
        void CopyNewNode(const int &l, const Node& n) {
            len = l, link = n.link;
            memcpy(ch, n.ch, sizeof(ch));
            //cnt = 0;
        }
    };
    
    const int MAXN = 250000;
    
    //SuffixAutomaton
    struct SAM {
        Node nd[(MAXN << 1) + 5];
        int top, last;  //top为节点个数,last末尾节点的位置
    
        void init() {
            nd[1].NewNode();
            top = 1, last = 1;
        }
    
        void extend(char ch) {
            int c = ch - 'a';
            int p = last, x = last = ++top;
            nd[x].NewNode(nd[p].len + 1);
            for(; p && !nd[p].ch[c]; p = nd[p].link)
                nd[p].ch[c] = x;
            if(!p)
                nd[x].link = 1;
            else {
                int q = nd[p].ch[c];
                if(nd[p].len + 1 == nd[q].len)
                    nd[x].link = q;
                else {
                    int y = ++top;
                    nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
                    nd[q].link = nd[x].link = y;
                    for(; p && nd[p].ch[c] == q; p = nd[p].link)
                        nd[p].ch[c] = y;
                }
            }
        }
    
        int LongestCommonSubstring(char *t) {
            int ans = 0;
            int u = 1, len = 0;
            int n = strlen(t);
            int endpos = 0;
            for(int i = 0; i < n; ++i) {
                int c = t[i] - 'a';
                while(!nd[u].ch[c] && nd[u].link) {
                    u = nd[u].link;
                    len = nd[u].len;
                }
                if(nd[u].ch[c]) {
                    u = nd[u].ch[c];
                    ++len;
                    if(len > ans) {
                        ans = len;
                        endpos = i;
                    }
                }
    
            }
            /*for(int i = endpos - ans + 1; i <= endpos; ++i)
                putchar(t[i]);
            putchar('
    ');*/
            return ans;
        }
    
    } sam;
    
    char s[MAXN + 5], t[MAXN + 5];
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        scanf("%s%s", s, t);
        sam.init();
        for(int i = 0; s[i] != ''; ++i)
            sam.extend(s[i]);
        printf("%d
    ", sam.LongestCommonSubstring(t));
    }
    

    多个字符串的LCS。又WA又T。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int INF = 0x3f3f3f3f;
    
    struct Node {
        int len, link;
        int ch[26];
        void NewNode(int l = 0) {
            len = l, link = 0;
            //memset(ch, 0, sizeof(ch));
        }
        void CopyNewNode(const int &l, const Node& n) {
            len = l, link = n.link;
            memcpy(ch, n.ch, sizeof(ch));
        }
    };
    
    const int MAXLEN = 100000;
    const int MAXNODE = 2 * MAXLEN + 5;
    
    //SuffixAutomaton
    struct SAM {
        Node nd[MAXNODE];
        int top, last;  //top为节点个数,last末尾节点的位置
    
        int minlen[MAXNODE], curlen[MAXNODE];
    
        void init() {
            nd[1].NewNode();
            top = 1, last = 1;
            memset(minlen, INF, sizeof(minlen));
        }
    
        void extend(char ch) {
            int c = ch - 'a';
            int p = last, x = last = ++top;
            nd[x].NewNode(nd[p].len + 1);
            for(; p && !nd[p].ch[c]; p = nd[p].link)
                nd[p].ch[c] = x;
            if(!p)
                nd[x].link = 1;
            else {
                int q = nd[p].ch[c];
                if(nd[p].len + 1 == nd[q].len)
                    nd[x].link = q;
                else {
                    int y = ++top;
                    nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
                    nd[q].link = nd[x].link = y;
                    for(; p && nd[p].ch[c] == q; p = nd[p].link)
                        nd[p].ch[c] = y;
                }
            }
        }
    
        int d[MAXNODE];
        int que[MAXNODE], front, back;
    
        void updateLink() {
            //别忘记沿着link更新各位祖先的长度
            front = 1, back = 0;
            for(int i = top; i >= 1; --i)
                ++d[nd[i].link];
            for(int i = top; i >= 1; --i)
                if(!d[i])
                    que[++back] = i;
            while(back >= front) {
                int u = que[front++], v = nd[u].link;
    
                //它的link祖先的LCS长度不能超过他自己的长度
                int t = curlen[u] < nd[v].len ? curlen[u] : nd[v].len;
                if(t > curlen[v])
                    curlen[v] = t;
    
                if(minlen[u] > curlen[u])
                    minlen[u] = curlen[u];
                curlen[u] = 0;
    
                if(!(--d[v]))
                    que[++back] = v;
            }
        }
    
        void LongestCommonSubstringHelp(char *t) {
            int u = 1, len = 0;
            for(int i = 0; t[i]; ++i) {
                int c = t[i] - 'a';
                while(!nd[u].ch[c] && nd[u].link) {
                    u = nd[u].link;
                    len = nd[u].len;
                }
    
                if(nd[u].ch[c]) {
                    u = nd[u].ch[c];
                    ++len;
    
                    if(len > curlen[u])
                        curlen[u] = len;
                }
            }
    
            updateLink();
            return;
        }
    
        int LongestCommonSubstring() {
            int ans = 0;
            for(int i = top; i >= 1; --i)
                ans = max(ans, minlen[i]);
            return ans;
        }
    
    } sam;
    
    char s[MAXLEN], t[MAXLEN];
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        scanf("%s", s);
        sam.init();
        for(int i = 0; s[i] != ''; ++i)
            sam.extend(s[i]);
        while(~scanf("%s", t))
            sam.LongestCommonSubstringHelp(t);
    
        printf("%d
    ", sam.LongestCommonSubstring());
    
    }
    
  • 相关阅读:
    监控Redis集群
    host主机监控规则
    Prometheus自身的监控告警规则
    Prometheus alerts 各种告警规则
    Elasticsearch官方文档离线访问实操指南
    Ceph 存储集群
    采用阿里云 yum的方式安装ceph
    设置HTTP请求自动跳转HTTPS
    jumpserver 2222端口的使用
    安装jumpserver 2.1.2版本遇到的坑
  • 原文地址:https://www.cnblogs.com/Yinku/p/11257552.html
Copyright © 2011-2022 走看看