• P3804 【模板】后缀自动机 (SAM)


    空字符节点为状态1,而且这个空状态也是放在基数排序里面排序过的

    还有关于clone的节点啊,要注意 他的siz一开始是设成0的

     我们注意到clone节点 ++size时,没有把这个状态的siz设成1,而是0,因为这个状态是拆开的,所以后面DFS累加的时候累加上来就是原值,防止重复计算。感性理解一下把

    然后

    后缀自动机有两种链 ,一种是link的后缀连接,从尾一直连到头,头也就是空字串节点,从后往前走依次累加可以获得每个状态串的出现次数

    一种是trans的转移连接,然后这个是从头也就是空串节点,连到尾,每次连接的新状态,长度只+1;

    这两种连接是完全不同的。

    链接: https://www.luogu.com.cn/problem/P3804

    基数排序模拟DFS

    因为maxlen大的一定在树的下面

    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i=a;i<=n;++i)
    #define per(i,a,n) for(int i=n;i>=a;--i)
    #define pb push_back
    #define fi first
    #define se second
    #define io std::ios::sync_with_stdio(false)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    
    ll gcd(ll a,ll b)
    {
        return b?gcd(b,a%b):a;
    }
    ll qpow(ll a,ll n)
    {
        ll r=1%P;
        for (a%=P; n; a=a*a%P,n>>=1)if(n&1)r=r*a%P;
        return r;
    }
    const int maxn=2e6;
    
    struct Suffix_Automata {
      int maxlen[maxn], trans[maxn][26], link[maxn], Size, Last;
      int siz[maxn];
      Suffix_Automata() { Size = Last = 1; }
      inline void Extend(int id) {
        int cur = (++ Size), p;
        siz[Size]=1;
        maxlen[cur] = maxlen[Last] + 1;
        for (p = Last; p && !trans[p][id]; p = link[p]) trans[p][id] = cur;
        if (!p) link[cur] = 1;
        else {
          int q = trans[p][id];
          if (maxlen[q] == maxlen[p] + 1) link[cur] = q;
          else {
            int clone = (++ Size);
            maxlen[clone] = maxlen[p] + 1;
            memcpy(trans[clone], trans[q],sizeof(trans[q]));
            link[clone] = link[q];
            for (; p && trans[p][id] == q; p = link[p]) trans[p][id] = clone;
            link[cur] = link[q] = clone;
          }
        } 
        Last = cur;
      }
    } T;
    int t[maxn],A[maxn];
    
    int main()
    {
         char s[maxn];
         cin>>s+1;
         int n=strlen(s+1);
         for(int i=1;i<=n;i++)
         {
           T.Extend(s[i]-'a');
         }
         ll ans=0;
        
        for(int i=1;i<=T.Size;i++) t[T.maxlen[i]]++;//放入桶
        for(int i=1;i<=n;i++) t[i]+=t[i-1];//累加排名
        for(int i=1;i<=T.Size;i++) A[t[T.maxlen[i]]--]=i;//排第几的是i,同时桶--
    
        for(int i=T.Size;i>=1;i--)
        {
              int now=A[i];
              T.siz[T.link[now]]+=T.siz[now];
              if(T.siz[now]>1) ans=max(ans,1ll*T.siz[now]*T.maxlen[now]);
        }
       cout<<ans<<endl;
    
    }
  • 相关阅读:
    ^_^【CSS代码规范】规则顺序
    【html】三
    【代码组织】♣一
    LINUX nautilus 命令
    hadoop 统计一个目录的文件大小
    hadoop基本配置信息
    linux中用到的命令
    简单的hadoop配置(我安装的问题)
    hadoop不能用root用户启动,会报错
    linux 下的ps与jps
  • 原文地址:https://www.cnblogs.com/acmLLF/p/13496572.html
Copyright © 2020-2023  润新知