HDu4416 Good Article Good sentence (后缀自动机)

题解:先对每个模式串建立一个后缀自动机,计算出子串的种类个数,再把文本串加上去,再计算一次子串种类个数,最后相减就好了

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 2e5 + 50;
int n, m;
string s, t;
struct state
{
    int link, nex[26];
    int len;
} st[maxn * 2];

int last, sz;
void sam_init(){
    for(int i = 0; i < 26; i++) st[0].nex[i] = 0;
    last = 0;
    st[last].link = -1;
    st[last].len = 0;
    sz = 1;
}
void init_nex(int u){
    for(int i = 0; i < 26; i++) st[u].nex[i] = 0;
}
void sam_extend(int x){
    if(st[last].nex[x]){
    	int q = st[last].nex[x];
    	if(st[q].len == st[last].len + 1){
    		last = q;
    		return ;
    	}
    }
    int cur = sz++;
    init_nex(cur);
    st[cur].len = st[last].len + 1;
    int p = last;
    while(p != -1 && !st[p].nex[x]) {
        st[p].nex[x] = cur;
        p = st[p].link;
    }
    if(p == -1) st[cur].link = 0;
    else{
        int q = st[p].nex[x];
        if(st[q].len == st[p].len + 1){
            st[cur].link = q;
        } else {
            int clone = sz++;
            st[clone].link = st[q].link;
            st[clone].len = st[p].len + 1;
            for(int i = 0; i < 26; i++) st[clone].nex[i] = st[q].nex[i];
            while(p != -1 && st[p].nex[x] == q){
                st[p].nex[x] = clone;
                p = st[p].link;
            }
            st[q].link = st[cur].link = clone;
        }
    }
    last = cur;
}
int main(int argc, char const *argv[])
{
    int tt;
    cin >> tt;
    int ca = 0;
    while(tt--){
        sam_init();
        cin >> n;
        cin >> t;
        for(int i = 1; i <= n; i++){
            cin >> s;
            last = 0;
            int len = s.size();
            for(int j = 0; j < len; j++){
                sam_extend(s[j] - 'a');
            }
        }
        LL ans1 = 0;
        for(int i = 1; i < sz; i++){
        	ans1 += st[i].len - st[st[i].link].len;
        }
        int len = t.size();
        last = 0;
        for(int i = 0; i < len; i++){
            sam_extend(t[i] - 'a');
        }
        LL ans = 0;
        for(int i = 1; i < sz; i++) {
            ans += st[i].len - st[st[i].link].len;
        }

        printf("Case %d: %I64d\n", ++ca, ans - ans1);
    }
    return 0;
}
posted @ 2020-08-05 14:57  从小学  阅读(102)  评论(0编辑  收藏  举报