luogu 字符串口胡合集

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\n",sum);
    }
    return 0;
}
View Code

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\n",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Hugh-Locke/p/11761394.html
今日推荐