zoukankan      html  css  js  c++  java
  • BZOJ 3473: 字符串 [广义后缀自动机]

    3473: 字符串

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 354  Solved: 160
    [Submit][Status][Discuss]

    Description

    给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串?

    Input

    第一行两个整数n,k。
    接下来n行每行一个字符串。

    Output

    一行n个整数,第i个整数表示第i个字符串的答案。
    字符串总长度L
    n,k,L<=1e5

    研究了两节多课广义后缀自动机是什么,还看了2015国家队论文,然后发现,广义后缀自动机不就是把很多串的SAM建到了一个SAM上,建每个串的时候都从root开始(last=root)就行了........
    广义后缀自动机是Trie树的后缀自动机,可以解决多主串问题
    这样的在线构造算法复杂度为O(G(T)),G(T)为Trie树上所有叶子节点深度和,发现G(T)<=所有主串总长度
    还有一种离线算法,复杂度O(|T||A|) ,不学了吧
     
    对于本题,建出广义SAM后,只要得到每个状态出现在不同串中的次数就好做了
    我们跑每个子串,然后更新状态
    状态维护cou和cur分别为出现次数及上一次出现是哪个串,然后就可以不重复的统计啦
    出现次数向父亲传递,所以要沿着Parent向上跑更新,遇到cur=当前串的就不用继续跑了,这样最坏情况下复杂度为O(L^3/2),发生在n=L的时候(均值不等式啊)
     
    剩下的只要DP出f[i]为i及其Parent祖先出现次数>=k有多少字符串(注意一个状态贡献的字符串为t[par].val-t[u].val),然后在跑一遍每个字符串得到答案就行了
     
    注意sz也要=1啊啊啊啊啊啊啊啊啊再让你作死写新模板
     
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <string>
    using namespace std;
    const int N=2e5+5;
    typedef long long ll;
    int n,k;
    string s[N>>1];
    char ss[N>>1];
    struct node{
        int ch[26],par,val;
        int cou,cur;
    }t[N];
    int sz=1,root=1,last=1;
    void extend(int c){
        int p=last,np=++sz;
        t[np].val=t[p].val+1;
        for(;p&&!t[p].ch[c];p=t[p].par) t[p].ch[c]=np;
        if(!p) t[np].par=root;
        else{
            int q=t[p].ch[c];
            if(t[q].val==t[p].val+1) t[np].par=q;
            else{
                int nq=++sz;
                t[nq]=t[q];t[nq].val=t[p].val+1;
                t[q].par=t[np].par=nq;
                for(;p&&t[p].ch[c]==q;p=t[p].par) t[p].ch[c]=nq;
            }
        }
        last=np;
    }
    int c[N],a[N];
    ll f[N];
    void RadixSort(){
        for(int i=1;i<=sz;i++) c[t[i].val]++;
        for(int i=1;i<=sz;i++) c[i]+=c[i-1];
        for(int i=sz;i>=1;i--) a[c[t[i].val]--]=i;
    }
    void solve(){
        int u;ll ans;
        for(int i=1;i<=n;i++){//printf("i %d
    ",i);
            u=root;
            for(int j=0;j<s[i].size();j++){
                u=t[u].ch[s[i][j]-'a'];//printf("u %d  %d  %d
    ",u,t[u].cou,j);
                int p=u;
                for(;p&&t[p].cur!=i;p=t[p].par) t[p].cou++,t[p].cur=i;
            }
        }
        RadixSort();
        for(int i=1;i<=sz;i++) u=a[i];
        t[1].cou=0;
        for(int i=1;i<=sz;i++) u=a[i],f[u]=f[t[u].par]+(t[u].cou>=k?t[u].val-t[t[u].par].val:0);
        for(int i=1;i<=n;i++){
            u=root;ans=0;
            for(int j=0;j<s[i].size();j++){
                u=t[u].ch[s[i][j]-'a'];
                ans+=f[u];
            }
            printf("%lld ",ans);
        }
    }
    int main(){
        freopen("in","r",stdin);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%s",ss),s[i]=string(ss);
            last=root;
            for(int j=0;j<s[i].size();j++) extend(s[i][j]-'a');
        }
        solve();
    }
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    pycharm快捷键
    类变量、实例变量--python
    内置窗口 pyqt5
    Python GUI教程(六):使用Qt设计师进行窗口布局
    PyCharm中Qt Designer+PyUIC配置
    PyQT5堆叠布局:切换界面(QStackedLayout)
    面试题之位运算的巧妙应用
    mybatis之Mapped Statements collection does not contain value for...错误原因分析
    tomcat报错Exception loading sessions from persistent storage解决方案
    leetcode数据库sql之Delete Duplicate Emails
  • 原文地址:https://www.cnblogs.com/candy99/p/6381066.html
Copyright © 2011-2022 走看看