P3065 [USACO12DEC]第一!First!
建立trie树,对于每个字符串的每个字符,容易想到必定小于他的兄弟字符,用拓扑排序判断是否有冲突即可
P4070 [SDOI2016]生成魔咒
求S每个前缀有多少本质不同的子串
可知SAM每次加入一个字符后增加的本质不同的字符串是新增的结点maxlen[np] - minlen[np] + 1 = len[np] - len[fa[np]]

#include<bits/stdc++.h> using namespace std; #define LL long long const int maxn = 1e5 + 10; int len[maxn << 1],fa[maxn << 1]; unordered_map<int,int> son[maxn << 1]; int size,last; void Init(){ size = last = 1; } int insert(int s){ int p = last,np= ++size; last = np; len[np] = len[p] + 1; for(;p && !son[p].count(s);p = fa[p]) son[p][s] = np; if(!p) fa[np] = 1; else{ int q = son[p][s]; if(len[p] + 1 == len[q]) fa[np] = q; else{ int nq = ++size; len[nq] = len[p] + 1; son[nq] = son[q]; fa[nq] = fa[q]; fa[q] = fa[np] = nq; for(;son[p].count(s) && son[p][s] == q && p;p = fa[p]) son[p][s] = nq; } } // cout << len[last] << " " << len[fa[last]] << endl; return len[last] - len[fa[last]]; } int N; int main(){ scanf("%d",&N); LL sum = 0; Init(); for(int i = 1; i <= N ; i ++){ int x; scanf("%d",&x); sum += insert(x); printf("%lld ",sum); } return 0; }
P3346 [ZJOI2015]诸神眷顾的幻想乡
学了一下广义后缀自动机(似乎就是把所有字符串建在同一个SAM上),然后她就是模板题了

#include<bits/stdc++.h> using namespace std; #define LL long long const int maxn = 1e6 + 10; int len[maxn << 1],fa[maxn << 1]; int son[maxn << 1][10]; int size; void Init(){ size = 1; } int insert(int s,int last){ int p = last,np= ++size; len[np] = len[p] + 1; for(;p && !son[p][s];p = fa[p]) son[p][s] = np; if(!p) fa[np] = 1; else{ int q = son[p][s]; if(len[p] + 1 == len[q]) fa[np] = q; else{ int nq = ++size; len[nq] = len[p] + 1; memcpy(son[nq],son[q],sizeof(son[q])); fa[nq] = fa[q]; fa[q] = fa[np] = nq; for(;son[p][s] && son[p][s] == q && p;p = fa[p]) son[p][s] = nq; } } return np; } int N,c; struct Edge{ int to,next; }edge[maxn * 2]; int head[maxn],tot; void init(){ for(int i = 0 ; i <= N ; i ++) head[i] = -1; tot = 0; } void add(int u,int v){ edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } int a[maxn]; int ind[maxn]; void dfs(int u,int la,int last){ last = insert(a[u],last); for(int i = head[u]; ~i ; i = edge[i].next){ int v = edge[i].to; if(v == la) continue; dfs(v,u,last); } } int main(){ scanf("%d%d",&N,&c); Init(); init(); for(int i = 1; i <= N ; i ++) scanf("%d",&a[i]); for(int i = 1; i <= N - 1; i ++){ int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); ind[u]++; ind[v]++; // cout << u << " " << v << endl; } for(int i = 1; i <= N ; i ++){ if(ind[i] == 1){ dfs(i,-1,1); } // cout << i << " " << ind[i] << endl; } LL ans = 0; for(int i = 1; i <= size; i ++) ans += len[i] - len[fa[i]]; printf("%lld ",ans); return 0; }