zoukankan      html  css  js  c++  java
  • SETI ACdream

    http://blog.csdn.net/gatevin/article/details/45875343

    题目是求不重叠的不同子串个数

    一般来说,

    endpos集合包含了子串结尾位置,结尾在"3、4、6"等

    每个状态都包含了若干个连续子串。就是"aabab", "abbab", "bbab", "bab"属于同一个状态

    endpos集合的大小就是这些子串的出现次数

    但是这样会重叠。那么可以求出endpos结合的结尾最小值,和结尾最大值。

    那么长度小于mx - mi的子串,是肯定不会重叠的

    至于有多少个,可以由mxcnt决定

    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 10000 + 2, N = 26;
    struct Node {
        int mxCnt; //mxCnt表示后缀自动机中当前节点识别子串的最大长度
        int miCnt; //miCnt表示后缀自动机中当前节点识别子串的最小长度
        int id; //表示它是第几个后缀自动机节点,指向了它,但是不知道是第几个,用id判断
        int mxPos, miPos; //pos表示它在原串中的位置。
        bool flag; //表示当前节点是否能识别前缀
        struct Node *pNext[N], *fa;
    }suffixAutomaton[maxn * 2], *root, *last; //大小需要开2倍,因为有一些虚拟节点
    int t;  //用到第几个节点
    struct Node *create(int mxCnt = -1, struct Node *node = NULL) { //新的节点
        if (mxCnt != -1) {
            suffixAutomaton[t].mxCnt = mxCnt, suffixAutomaton[t].fa = NULL;
            for (int i = 0; i < N; ++i) suffixAutomaton[t].pNext[i] = NULL;
        } else {
            suffixAutomaton[t] = *node; //保留了node节点所有的指向信息。★全部等于node
            //可能需要注意下pos,在原串中的位置。现在pos等于原来node的pos
        }
        suffixAutomaton[t].id = t;  //必须要有的,不然id错误
        suffixAutomaton[t].flag = false; //默认不是前缀节点
        return &suffixAutomaton[t++];
    }
    void addChar(int x, int pos) { //pos表示在原串的位置
        struct Node *p = last, *np = create(p->mxCnt + 1, NULL);
        np->flag = true;
        np->mxPos = np->miPos = pos, last = np; //last是最尾那个可接收后缀字符的点。
        for (; p != NULL && p->pNext[x] == NULL; p = p->fa) p->pNext[x] = np;
        if (p == NULL) {
            np->fa = root;
            np->miCnt = 1; // 从根节点引一条边过来
            return;
        }
        struct Node *q = p->pNext[x];
        if (q->mxCnt == p->mxCnt + 1) { //中间没有任何字符,可以用来代替接受后缀、
            np->fa = q;
            np->miCnt = q->mxCnt + 1; // q是状态8的"ab",np是状态7的"bab"长度是2+1
            return;
        }
        // p: 当前往上爬到的可以接受后缀的节点
        // np:当前插入字符x的新节点
        // q: q = p->pNext[x],q就是p中指向的x字符的节点
        // nq:因为q->cnt != p->cnt + 1而新建出来的模拟q的节点
        struct Node *nq = create(-1, q); // 新的q节点,用来代替q,帮助np接收后缀字符
        nq->mxCnt = p->mxCnt + 1; //就是需要这样,这样中间不包含任何字符
        q->miCnt = nq->mxCnt + 1, np->miCnt = nq->mxCnt + 1;
        q->fa = nq, np->fa = nq; //现在nq是包含了本来q的所有指向信息
        for (; p && p->pNext[x] == q; p = p->fa) {
            p->pNext[x] = nq;
        }
    }
    void init() {
        t = 0;
        root = last = create(0, NULL);
    }
    void build(char str[], int lenstr) {
        init();
        for (int i = 1; i <= lenstr; ++i) addChar(str[i] - 'a', i);
    }
    char str[maxn];
    queue<int> que;
    int dp[maxn * 2], in[maxn * 2];
    void work() {
        scanf("%s", str + 1);
        build(str, strlen(str + 1));
        for (int i = 1; i < t; ++i) {
            in[suffixAutomaton[i].fa->id]++;
        }
        for (int i = 1; i < t; ++i) {
            if (in[i] == 0) que.push(i);
        }
        while (!que.empty()) {
            int cur = que.front();
            que.pop();
            if (!cur) break;
            int fa = suffixAutomaton[cur].fa->id;
            suffixAutomaton[fa].mxPos = max(suffixAutomaton[fa].mxPos, suffixAutomaton[cur].mxPos);
            in[fa]--;
            if (in[fa] == 0) que.push(fa);
        }
        LL ans = 0;
        for (int i = 1; i < t; ++i) {
            int dis = suffixAutomaton[i].mxPos - suffixAutomaton[i].miPos;
            int mi = min(suffixAutomaton[i].mxCnt, dis);
            if (dis < suffixAutomaton[i].miCnt) continue;
            ans += mi - suffixAutomaton[i].miCnt + 1;
        }
        printf("%lld
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    开心网注册详解和邀请码发放
    3COM 905TX 配置
    SQL使用
    JDBC的使用
    kiko日记几个月以来工作总结2010 1124
    talk about the history of JAZZ
    这几个月的工作任务
    工作间期的不足
    转: mac使用nvm管理多个版本node
    负载均衡与ssl证书
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/7504660.html
Copyright © 2011-2022 走看看