好久没写题解了唔.....
今天水了一题...写一下吧...
题目大意:
就是现在给出长度不超过10W的只包含小写字母的字符串,从下标0到 length - 1
现在从下标0开始进行操作
每次对于下标 i , 输出下标i开始的子串中最长的在其他地方出现过的串的长度, 其它出现的位置要求起点在位置i之前, 然后i移动到这个长度之后继续操作
如果没有这样的最长的串就直接i++, 继续操作
重复上面的操作直到 i == length
如果进行了i++, 输出-1和s[i]的ASCII码的值
如果进行了 i += K, 输出最大长度K以及这种串最左边出现的位置
(貌似现场赛这个题数据范围被缩小了, 于是成了一个全场都能过的题....)
大致思路:
很容易发现就是询问位置i开始的后缀和以位置[0...i - 1]开始的所有后缀中最大匹配的公共前缀长度
不难发现就是后缀自动机的水题
每次在询问i位置的时候, 一遍向后匹配一个位置一遍将那个位置加入自动机即可,一边匹配一边加入, 可以保证询问i位置的时候, i - 1位置能提供的最大长度也是可以保证的, 正确性显然, (后缀自动机在添加字符的时候注意记录最左边一次出现的位置(我记录的是第一次出现的结尾位置即可)
匹配操作的话就是从当前后缀自动机的根节点向后遍历, 只要从当前结点向下的go指针非空就说明之前有这样的串
因为每次i在向后多匹配一个位置的时候, i就会后移, 最多只会移动length次, 所以时间复杂度是O(length(S)) 也就是所有串的总长度
代码如下:
Result : Accepted Memory : 42476 KB Time : 592 ms
/* * Author: Gatevin * Created Time: 2015/11/20 10:23:20 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define maxn (100010*2) #define maxm 100010 struct Suffix_Automation { struct State { State *par; State *go[26]; int val; int mi; int cnt; int right; int leftmost; void init(int _val = 0) { par = 0, val = _val, cnt = 0, mi = 0, right = 0, leftmost = 1e9; memset(go, 0, sizeof(go)); } }; State *root, *last, *cur; State nodePool[maxn]; State* newState(int val = 0) { cur->init(val); return cur++; } void initSAM() { cur = nodePool; root = newState(); last = root; } void extend(int w, int head) { State *p = last; State *np = newState(p->val + 1); np->right = 1; np->leftmost = head; while(p && p->go[w] == 0) { p->go[w] = np; p = p->par; } if(p == 0) { np->par = root; } else { State *q = p->go[w]; if(p->val + 1 == q->val) { np->par = q; } else { State *nq = newState(p->val + 1); memcpy(nq->go, q->go, sizeof(q->go)); nq->leftmost = q->leftmost; nq->par = q->par; q->par = nq; np->par = nq; while(p && p->go[w] == q) { p->go[w] = nq; p = p->par; } } } last = np; } void solve(char *s) { initSAM(); int n = strlen(s); int now = 0; while(now != n) { State* pos = root; int deep = 0; while(now < n && pos->go[s[now] - 'a'] != 0) { pos = pos->go[s[now] - 'a']; deep++; extend(s[now] - 'a', now); now++; } if(deep == 0) { extend(s[now] - 'a', now); printf("-1 %d\n", s[now++]); } else printf("%d %d\n", deep, pos->leftmost - deep + 1); } } }; Suffix_Automation sam; char s[maxm]; int main() { int T; scanf("%d", &T); for(int cas = 1; cas <= T; cas++) { printf("Case #%d:\n", cas); scanf("%s", s); sam.solve(s); } return 0; } /* 2 aaaaaa aaaaabbbbbaaabbc */