SETI ACdream - 1430 后缀自动机求不相交子串
Posted stupid_one
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SETI ACdream - 1430 后缀自动机求不相交子串相关的知识,希望对你有一定的参考价值。
http://blog.csdn.net/gatevin/article/details/45875343
题目是求不重叠的不同子串个数
一般来说,endpos集合包含了子串结尾位置,每个状态都包含了若干子串。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\n", ans); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
以上是关于SETI ACdream - 1430 后缀自动机求不相交子串的主要内容,如果未能解决你的问题,请参考以下文章