1. 程式人生 > >P4081 [USACO17DEC]Standing Out from the Herd

P4081 [USACO17DEC]Standing Out from the Herd

inline 英文字母 -- lin abcdefg 整數 沒有 下標 span

$ \color{#0066ff}{ 題目描述 }$

定義一個字符串的「獨特值」為只屬於該字符串的本質不同的非空子串的個數。如 "amy" 與 “tommy” 兩個串,只屬於 "amy" 的本質不同的子串為 "a" "am" "amy" 共 3 個。只屬於 "tommy" 的本質不同的子串為 "t" "to" "tom" "tomm" "tommy" "o" "om" "omm" "ommy" "mm" "mmy" 共 11 個。 所以 "amy" 的「獨特值」為 3 ,"tommy" 的「獨特值」為 11 。

給定 N (\(N \leq 10^5\)) 個字符集為小寫英文字母的字符串,所有字符串的長度和小於 \(10^5\),求出每個字符串「獨特值」。

\(\color{#0066ff}{輸入格式}\)

第一行包含一個正整數n,字符串個數

接下來是n個字符串

\(\color{#0066ff}{輸出格式}\)

每行一個答案

\(\color{#0066ff}{輸入樣例}\)

3
amy
tommy
bessie

\(\color{#0066ff}{輸出樣例}\)

3
11
19

\(\color{#0066ff}{數據範圍與提示}\)

none

\(\color{#0066ff}{題解}\)

把所有字符串用不同的字符隔開拼起來,建立SAM

那麽對於一個前綴,那些後綴會有貢獻呢?

當且僅當這個後綴沒有特殊字符!

那麽有多少個後綴有特殊字符呢,就是最近的那個特殊字符的下標

比如abcde¥fghij#klnmo,每一個字符串維護一個f,代表以當前字符串中任意位置為結尾的所有後綴,有多少不合法的

比如klnmo這個字符串,不合法的後綴數量為abcde¥fghij#的長度12

如果一個點是後綴節點,那麽它與它父親的邊上有一段是不合法的,就直接減去維護的f即可

否則直接有兩個len之差的貢獻

對於特殊字符,它不屬於任意一個字符串,所以雞排的時候順帶它向上的一條鏈都不合法

還有就是一個節點子樹中有來自不同字符串的節點,這也是不合法的,統統\(\in -1\)
就行

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int maxn = 4e5 + 100;
struct node {
    std::map<int, node*> ch;
    node *fa;
    int len, bel, siz;
    bool islast;
    node(int len = 0, int bel = 0, int siz = 0, bool islast = 0): len(len), bel(bel), siz(siz), islast(islast) {
        fa = NULL;
        ch.clear();
    }
}pool[maxn], *tail, *root, *lst;
LL ans[maxn];
int fuck[maxn];
node *id[maxn];
void extend(int c, int id) {
    node *o = new(tail++) node(lst->len + 1, id, 1), *v = lst;
    o->islast = true;
    for(; v && !v->ch.count(c); v = v->fa) v->ch[c] = o;
    if(!v) o->fa = root;
    else if(v->len + 1 == v->ch[c]->len) o->fa = v->ch[c];
    else {
        node *n = new(tail++) node(v->len + 1), *d = v->ch[c];
        n->ch = d->ch;
        n->fa = d->fa, d->fa = o->fa = n;
        for(; v && v->ch[c] == d; v = v->fa) v->ch[c] = n;
    }
    lst = o;
}
void getans() {
    int maxlen = 0, len = tail - pool;
    static int c[maxn];
    for(node *o = pool; o != tail; o++) maxlen = std::max(maxlen, o->len), c[o->len]++;
    for(int i = 1; i <= maxlen; i++) c[i] += c[i - 1];
    for(node *o = pool; o != tail; o++) id[--c[o->len]] = o;
    for(int i = len - 1; i; i--) {
        node *o = id[i];
        if(~o->bel) {
            if(o->islast) ans[o->bel] += o->len - o->fa->len - fuck[o->bel];
            else ans[o->bel] += o->len - o->fa->len;
        }
        else o->fa->bel = -1;
        if(!(~o->fa->bel)) continue;
        if(!o->fa->bel) o->fa->bel = o->bel;
        else if(o->fa->bel ^ o->bel) o->fa->bel = -1;
    }
}
void init() {
    tail = pool;
    root = lst = new(tail++) node();
}
char a[maxn];
int main() {
    int n = in();
    init();
    int cnt = 233;
    for(int i = 1; i <= n; i++) {
        if(i ^ 1) fuck[i] = fuck[i - 1] + strlen(a) + 1;
        scanf("%s", a);
        for(char *p = a; *p; p++) extend(*p, i);
        extend(++cnt, -1);
    }
    getans();
    for(int i = 1; i <= n; i++) printf("%lld\n", ans[i]);
    return 0;

}

P4081 [USACO17DEC]Standing Out from the Herd