1. 程式人生 > >【LG4070】[SDOI2016]生成魔咒

【LG4070】[SDOI2016]生成魔咒

構建 char break oid www. www org tchar ans

【LG4070】[SDOI2016]生成魔咒

題面

洛谷

題解

如果我們不用在線輸的話,那麽答案就是對於所有狀態\(i\)

\[ \sum (i.len-i.fa.len) \]

現在我們需要在線詢問,那麽因為\(SAM\)是在線算法,我們考慮每次的對答案的貢獻。

那麽產生的貢獻就是\(last.len-last.fa.len\)

\(yyb\)的對話:

Q:為什麽構建自動機時中間過程新加的點不會算到最後答案中呢?

A:不影響答案啊,你在兩個len之間斷開,對於答案的貢獻不變。

代碼

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm> 
#include <tr1/unordered_map> 
using namespace std;
using namespace std::tr1; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
    return w * data; 
} 
const int MAX_N = 1e5 + 5;
struct Node { 
    unordered_map<int, int> ch; 
    int len, fa; 
} t[MAX_N << 1];
int tot = 1, lst = 1;
long long ans = 0; 
void extend(int c) { 
    int New = ++tot;
    t[lst].ch[c] = New; 
    t[New].len = t[lst].len + 1; 
    int p = t[lst].fa; lst = tot; 
    while (p && t[p].ch.find(c) == t[p].ch.end()) t[p].ch[c] = New, p = t[p].fa; 
    if (!p) t[New].fa = 1;
    else { 
        int q = t[p].ch[c]; 
        if (t[q].len == t[p].len + 1) t[New].fa = q; 
        else { 
            int _q = ++tot; t[_q] = t[q]; 
            t[New].fa = t[q].fa = _q, t[_q].len = t[p].len + 1; 
            while (p) {
                unordered_map<int, int> :: iterator ite; 
                ite = t[p].ch.find(c); 
                if (ite == t[p].ch.end() || ite->second != q) break; 
                t[p].ch[c] = _q;
                p = t[p].fa; 
            } 
        } 
    } 
    ans += t[New].len - t[t[New].fa].len; 
} 

int main () {
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    int N = gi(); 
    for (int i = 1; i <= N; i++) extend(gi()), printf("%lld\n", ans); 
    return 0; 
} 

【LG4070】[SDOI2016]生成魔咒