[hdu4416 Good Article Good sentence]后缀自动机SAM

题意:给出串A和串集合B={B1,B2,...,Bn},求串A的所有不同子串中不是B中任一串的子串的数目。

思路:把A和B中所有字符串依次拼接在一起,然后构造后缀自动机,计算每个状态的R集合元素的最大值r,然后统计那些r≤length(A)的状态。hdu不卡时间卡空间,这是最郁闷的。。。导致下面的程序只在本地随机数据没发现错误,提交就MLE。

#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;

#ifndef ONLINE_JUDGE
    #include "local.h"
#endif

const int N = 6e5 + 7;

int len;

//注意空间为 DOUBLE SIZE
class SAM {
public:
    void init() {
        memset(node, 0, sizeof(node));
        sz = last = 0;
        node[0].len = 0;
        node[0].link = -1;
        sz ++;
    }
    void add(char c) {
        int cur = sz ++;
        node[cur].len = node[last].len + 1;
        node[cur].r = node[cur].len;
        int p;
        for (p = last; ~p && !node[p].next[c]; p = node[p].link) {
            node[p].next[c] = cur;
        }
        if (p == -1) node[cur].link = 0;
        else {
            int q = node[p].next[c];
            if (node[p].len + 1 == node[q].len) node[cur].link = q;
            else {
                int clone = sz ++;
                node[clone].link = node[q].link;
                memcpy(node[clone].next, node[q].next, sizeof(node[q].next));
                node[clone].len = node[p].len + 1;
                for (; ~p && node[p].next[c] == q; p = node[p].link) {
                    node[p].next[c] = clone;
                }
                node[q].link = node[cur].link = clone;
            }
        }
        last = cur;
    }
    int c[N], p[N];
    ll getAns() {
        mset(c, 0);
        for (int i = 0; i < sz; i ++) c[node[i].len] ++;
        for (int i = 1; i <= sz; i ++) c[i] += c[i - 1];
        for (int i = 0; i < sz; i ++) p[-- c[node[i].len]] = i;
        for (int i = sz - 1; i >= 0; i --) {
            int cur = p[i];
            if (cur == 0) continue;
            umax(node[node[cur].link].r, node[cur].r);
        }
        ll ans = 0;
        for (int i = 1; i < sz; i ++) {
            if (node[i].r <= len) ans += node[i].len - node[node[i].link].len;
        }
        return ans;
    }
private:
    const static int SZ = 27;
    struct State {
        int len, link;
        int r;
        int next[SZ];
    };
    State node[N];
    int sz, last;
};
SAM sam;
char s[N];

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    int n;
    cas() {
        cin >> n;
        sam.init();
        for (int i = -1; i < n; i ++) {
            scanf("%s", s);
            if (i < 0) len = strlen(s);
            for (int j = 0; s[j]; j ++) {
                sam.add(s[j] - 'a');
            }
            sam.add(26);
        }
        printf("Case %d: %I64d\n", ++ cas, sam.getAns());
    }
    return 0;
}

  

posted @ 2015-11-06 04:10  jklongint  阅读(262)  评论(0编辑  收藏  举报