BZOJ 2251 2010Beijing WC 外星联络 后缀数组/Trie树

来源:互联网 发布:js 对象数组 编辑:程序博客网 时间:2024/05/15 11:25

题目大意

给出一个字符串,问这个字符串中出现过1次以上的子串的个数,按照子串的字典序输出。

思路

由于数据范围过小,这个题有两个解法。
基本的想法就是用后缀数组来进行后缀的排序,之后按照height数组扫就可以了。应该是挺快的。
但是注意到数据范围只有3000,因此我们只需要弄出所有的后缀拿出来建立一颗后缀Trie树就行了。最后DFS一次树种的所有节点。

CODE

SuffixArray

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 3010using namespace std;int len;char s[MAX];int sa[MAX],val[MAX];inline bool Same(int x,int y,int l){    return val[x] == val[y] &&    ((x + l >= len && y + l >= len) || (x + l < len && y + l < len && val[x + l] == val[y + l]));}void GetSuffixArray(){    static int _val[MAX],q[MAX],cnt[MAX],lim = 256;    for(int i = 0; i < len; ++i) ++cnt[val[i] = s[i]];    for(int i = 1; i < lim; ++i) cnt[i] += cnt[i - 1];    for(int i = len - 1; ~i; --i)   sa[--cnt[val[i]]] = i;    for(int d = 1;; ++d) {        int top = 0,l = 1 << (d - 1);        for(int i = 0; i < len; ++i) if(sa[i] + l >= len) q[top++] = sa[i];        for(int i = 0; i < len; ++i) if(sa[i] >= l)   q[top++] = sa[i] - l;        for(int i = 0; i < lim; ++i) cnt[i] = 0;        for(int i = 0; i < len; ++i) ++cnt[val[q[i]]];        for(int i = 1; i < lim; ++i) cnt[i] += cnt[i - 1];        for(int i = len - 1; ~i; --i)   sa[--cnt[val[q[i]]]] = q[i];        lim = 0;        for(int i = 0,j; i < len; ++lim) {            for(j = i; j < len - 1 && Same(sa[j],sa[j + 1],l); ++j);            for(; i <= j; ++i)   _val[sa[i]] = lim;        }        for(int i = 0; i < len; ++i) val[i] = _val[i];        if(len == lim)  break;    }    return ;}int height[MAX],_rank[MAX];void GetHeight(){    for(int i = 0; i < len; ++i) _rank[sa[i]] = i;    for(int i = 0,k = 0; i < len; ++i) {        if(!_rank[i])   continue;        if(k)   --k;        int j = sa[_rank[i] - 1];        while(s[i + k] == s[j + k]) ++k;        height[_rank[i]] = k;    }}int main(){    scanf("%d%s",&len,s);    GetSuffixArray();    GetHeight();    for(int i = 0; i < len; ++i)        for(int j = height[i] + 1,l,r; sa[i] + j - 1 < len; ++j) {            for(l = i; ~l && height[l] >= j; --l);            for(r = i + 1; r < len && height[r] >= j; ++r);            if(r - l > 1)    printf("%d\n",r - l);        }    return 

SuffixTrie

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 10010using namespace std;struct Trie{    Trie *son[2];    int cnt;    Trie():cnt(0) {        son[0] = son[1] = NULL;    }}*root = new Trie();int length;char s[MAX];inline void Insert(char *s){    Trie *now = root;    while(*s != '\0') {        if(now->son[*s == '1'] == NULL)            now->son[*s == '1'] = new Trie();        now = now->son[*s == '1'];        ++now->cnt;        ++s;    }}void DFS(Trie *now){    if(now == NULL) return ;    if(now->cnt > 1)    printf("%d\n", now->cnt);    DFS(now->son[0]);    DFS(now->son[1]);}int main(){    scanf("%d%s", &length, s);    for(int i = 0; i < length; ++i)        Insert(s + i);    DFS(root);    return 0;}
0 0
原创粉丝点击