zoukankan      html  css  js  c++  java
  • [HDU4416] Good Article Good sentence

    Description

    给定主串 (S) 和若干个模式串 (T_1,T_2,...,T_n),问 (S) 的子串中有多少个不是 (T_1,T_2,...,T_n) 中任意一个串的子串。

    Solution

    (S) 建立 SAM,则一个结点对应了 (S) 的若干个子串

    (T_i) 放上去跑时,若跑到了一个结点 (p),此时匹配的长度为 (l),则该结点以及其后缀链接上所有节点表示的长度 (le l) 的子串都被废弃

    于是考虑对每个结点维护一个匹配过的最大长度 (f[i]),统计结点 (i) 的答案时,贡献为 (len[i]-max(f[i],minlen[i]))

    暴力维护需要每次修改一条链,实际上我们只需要在当前匹配的位置打标记,然后沿着后缀树上传取 max 即可

    (注意没有对应出边时的处理)

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 210005;
    const int dbg = 0;
    
    int max(int x,signed y)
    {
        return max(1ll*x,1ll*y);
    }
    
    int max(signed x,int y)
    {
        return max(1ll*x,1ll*y);
    }
    
    int min(int x,signed y)
    {
        return min(1ll*x,1ll*y);
    }
    
    int min(signed x,int y)
    {
        return min(1ll*x,1ll*y);
    }
    
    
    struct SAM
    {
        signed len[N], ch[N][26], fa[N], ind, last;
        int t[N], a[N], cnt[N], f[N];
        SAM()
        {
            ind = last = 1;
        }
        void init()
        {
            ind = last = 1;
            memset(len,0,sizeof len);
            memset(ch,0,sizeof ch);
            memset(fa,0,sizeof fa);
            memset(t,0,sizeof t);
            memset(a,0,sizeof a);
            memset(cnt,0,sizeof cnt);
            memset(f,0,sizeof f);
        }
        inline void extend(int id)
        {
            int cur = (++ ind), p;
            len[cur] = len[last] + 1;
            cnt[cur] = 1;
            for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur;
            if (!p) fa[cur] = 1;
            else
            {
                int q = ch[p][id];
                if (len[q] == len[p] + 1) fa[cur] = q;
                else
                {
                    int tmp = (++ ind);
                    len[tmp] = len[p] + 1;
                    for(int i=0; i<26; i++) ch[tmp][i] = ch[q][i];
                    fa[tmp] = fa[q];
                    for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp;
                    fa[cur] = fa[q] = tmp;
                }
            }
            last = cur;
        }
        void calc()
        {
            memset(t, 0, sizeof t);
            for(int i=1; i<=ind; i++) t[len[i]]++;
            for(int i=1; i<=ind; i++) t[i]+=t[i-1];
            for(int i=1; i<=ind; i++) a[t[len[i]]--]=i;
            for(int i=ind; i>=1; --i) cnt[fa[a[i]]]+=cnt[a[i]];
            cnt[1] = 0;
        }
        void run(string str)
        {
            int p=1,l=0;
            for(int i=0;i<str.length();i++)
            {
                int c=str[i]-'a';
                if(ch[p][c])
                {
                    p=ch[p][c];
                    l++;
                }
                else
                {
                    while(p&&ch[p][c]==0) p=fa[p];
                    if(ch[p][c])
                    {
                        l=len[p];
                        p=ch[p][c];
                        l++;
                    }
                    else
                    {
                        p=1;
                        l=0;
                    }
                }
                f[p]=max(f[p],l);
            }
        }
        long long solve()
        {
            long long ans=0;
            for(int t=ind;t>=1;--t)
            {
                int i=a[t];
                ans+=len[i]-max(f[i],len[fa[i]]);
                f[fa[i]]=min(len[fa[i]],max(f[fa[i]],f[i]));
            }
            return ans;
        }
    } sam;
    
    void solve()
    {
        static int id = 0;
    
        int n;
        cin>>n;
        string s;
    
        vector <string> vec;
    
        sam.init();
        cin>>s;
        for(int i=0;i<s.length();i++) sam.extend(s[i]-'a');
    
        if(dbg)
        {
            for(int i=0;i<s.length();i++)
            {
                for(int j=i;j<s.length();j++)
                {
                    string tmp;
                    for(int k=i;k<=j;k++) tmp+=s[k];
                    vec.push_back(tmp);
                }
            }
        }
    
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            sam.run(s);
    
            if(dbg)
            {
                for(int i=0;i<vec.size();i++)
                {
                    auto now=vec.begin()+i;
                    if(s.find(*now)!=s.npos)
                    {
                        vec.erase(now);
                        --i;
                    }
                }
            }
        }
    
        sam.calc();
        cout<<"Case "<<++id<<": "<<sam.solve()<<endl;
        if(dbg)
        {
            for(int i=0;i<vec.size();i++)
            {
                int flag=0;
                for(int j=i+1;j<vec.size();j++)
                {
                    if(vec[i]==vec[j]) flag=1;
                }
                if(flag)
                {
                    vec.erase(vec.begin()+i);
                    --i;
                }
            }
            cout<<"ans = "<<vec.size()<<endl;
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        while(t--) solve();
    }
    
    /* Hack data
    5 5
    ccbbcbaabcccbabcbcaaaacabbaccccacaabcbbcbaabcccbabcbcaaaacabbaccccbaabcccbabcbcaaaacabbaccccbaabcccbabcbcaaaacabbacccacacaacabcbccbaabcabbbccaabbcbbcacabcaaacacabacbccbaacbcbcaac
    abab
    cc
    bbb
    abab
    cb
    */
    
    
  • 相关阅读:
    MIP技术进展月报第3期:MIP小姐姐听说,你想改改MIP官网?
    MIP技术进展月报第2期: 数据绑定,异步脚本加速
    WebP 在减少图片体积和流量上的效果如何?MIP技术实践分享
    改造MIP获得搜索青睐,轻松完成SEO
    MIP 技术进展月报:储存功能全新上线,MIP-Cache域名升级,校验更严谨
    【转】W3C中国与百度联合组织移动网页加速技术研讨会
    百度将与W3C中国召开MIP技术研讨会
    【公告】MIP组件审核平台故障-影响说明
    【公告】关于8.8MIP组件审核平台故障的说明
    MIP 移动网页加速器视频教程全新发布
  • 原文地址:https://www.cnblogs.com/mollnn/p/13591985.html
Copyright © 2011-2022 走看看