【洛谷 P2408】 不同子串个数(后缀自动机)

题目链接
裸体就是身体。
建出(SAM)(DAG)上跑(DP)(f[u]=1+sum_{(u,v)in DAG}f[v])
答案为(f[1]-1)(因为根节点没有字符)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1000010;
struct SAM{
    int ch[26];
    int len, fa;
}sam[MAXN << 1];
int las = 1, cnt = 1;
long long f[MAXN << 1];
inline void add(int c){
    int p = las; int np = las = ++cnt;
    sam[np].len = sam[p].len + 1;
    for(; p && !sam[p].ch[c]; p = sam[p].fa) sam[p].ch[c] = np;
    if(!p) sam[np].fa = 1;
    else{
        int q = sam[p].ch[c];
        if(sam[q].len == sam[p].len + 1) sam[np].fa = q;
        else{
            int nq = ++cnt; sam[nq] = sam[q];
            sam[nq].len = sam[p].len + 1;
            sam[q].fa = sam[np].fa = nq;
            for(; p && sam[p].ch[c] == q; p = sam[p].fa) sam[p].ch[c] = nq;
        }
    }
}
char a[MAXN];
long long ans;
void dfs(int u){
    f[u] = 1;
    for(int i = 0; i < 26; ++i)
        if(sam[u].ch[i]){
            if(!f[sam[u].ch[i]])
                dfs(sam[u].ch[i]);
            f[u] += f[sam[u].ch[i]];
        }
}
int len;
int main(){
    scanf("%d", &len);
    scanf("%s", a + 1);
    for(int i = 1; i <= len; ++i)
       add(a[i] - 'a');
    dfs(1);
    printf("%lld
", f[1] - 1);
    return 0;
}

原文地址:https://www.cnblogs.com/Qihoo360/p/10986643.html