码迷,mamicode.com
首页 > 其他好文 > 详细

后缀自动机

时间:2017-08-08 00:33:27      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:end   top   pre   接受   gets   style   struct   else   多少   

kuangbin 的模板

//begin{ kuangbin SAM }
struct SAM_Node {
  SAM_Node *fa, *next[CHAR];
  int len, id, pos;
  SAM_Node(int _len = 0): fa(0), len(_len), id(0), pos(0) {memset(next, 0, sizeof(next));}
};
SAM_Node SAM_node[MAXN * 2], *SAM_root, *SAM_last;
int SAM_size;
SAM_Node *newSAM_Node(int len) {SAM_node[SAM_size] = SAM_Node(len); SAM_node[SAM_size].id = SAM_size; return &SAM_node[SAM_size++];}
SAM_Node *newSAM_Node(SAM_Node *p) {SAM_node[SAM_size] = *p; SAM_node[SAM_size].id = SAM_size; return &SAM_node[SAM_size++];}
void SAM_init() {SAM_size = 0; SAM_root = SAM_last = newSAM_Node(0); SAM_node[0].pos = 0;}
void SAM_add(int x, int len) {
  SAM_Node *p = SAM_last, *np = newSAM_Node(p->len + 1);
  np->pos = len; SAM_last = np;
  for(; p && !p->next[x]; p = p->fa) p->next[x] = np;
  if(!p) { np->fa = SAM_root; return;}
  SAM_Node *q = p->next[x];
  if(q->len == p->len + 1) { np->fa = q; return;}
  SAM_Node *nq = newSAM_Node(q);
  nq->len = p->len + 1; q->fa = nq; np->fa = nq;
  for(; p && p->next[x] == q; p = p->fa) p->next[x] = nq;
}
void SAM_build(char *s) {
  SAM_init();
  int len = strlen(s);
  for(int i = 0; i < len; i++) SAM_add(s[i] - a, i + 1);
}

int topocnt[MAXN];
SAM_Node *topsam[MAXN * 2];
void topo() {
  int n = strlen(s);
  SAM_build(s);
  memset(topocnt, 0, sizeof(topocnt));
  for(int i = 0; i < SAM_size; i++)topocnt[SAM_node[i].len]++;
  for(int i = 1; i <= n; i++)topocnt[i] += topocnt[i - 1];
  for(int i = 0; i < SAM_size; i++)topsam[--topocnt[SAM_node[i].len]] = &SAM_node[i];
}
// end{kaungbin SAM}

 

求最长公共子串长度

char s1[MAXN], s2[MAXN];
void solve() {
  gets(s1); gets(s2);
  SAM_build(s1);
  int ans = 0;
  SAM_Node *p = SAM_root;
  for(int i = 0, t = 0, len = strlen(s2); i < len; ++i) {
    if(p->next[s2[i] - a]) {
      p = p->next[s2[i] - a];
      t++;
    } else {
      while(p != NULL && !p->next[s2[i] - a])  p = p->fa;
      if(p == NULL)  p = SAM_root, t = 0;
      else t = p->len + 1, p = p->next[s2[i] - a];
    }
    ans = std::max(ans, t);
  }
  printf("%d\n", ans);
}

求字典序最小循环移位(可用最小表示法)

char s1[MAXN];
void solve() {
  gets(s1); SAM_build(s1);
  int len = strlen(s1);
  for(int i = 0; i < len; ++i)  SAM_add(s1[i] - a, len + i + 1);
  SAM_Node *p = SAM_root;
  for(int i = 0, t = 0, len = strlen(s1); i < len; ++i) {
    int j = 0;
    while(p->next[j] == NULL && j < 26) j++;
    p = p->next[j];
  }
  int ans = p->pos - len + 1;
  printf("%d\n", ans);
}

依次输出长度为 i (from 1 to |s|) 的所有子串中出现的最多次数

 

const int MAXN = 500000+7;

//
r(表示当前状态可以在多少个位置上出现) // mi(当前状态能接受的串的最短长度,即 par->val+1) int r[MAXN],mi[MAXN],ret[MAXN]; void solve() { gets(s); topo(); int len = strlen(s); SAM_Node *p = SAM_root; for(int i = 0; i < len; ++i){ p = p->next[s[i]-a]; r[p->id] = 1; } for(int i = SAM_size - 1; i > 0; --i) { p = topsam[i]; r[p->fa->id] += r[p->id]; mi[p->id] = mi[p->fa->id]; } for(int i = 1;i < SAM_size;++i){ p = topsam[i]; ret[p->len] = std::max(ret[p->len],r[p->id]); //printf("f[%d]=%d\n",p->len,r[p->id]); } for(int i = len-1;i>0;--i) ret[i] = std::max(ret[i+1],ret[i]); for(int i = 1;i <= len;++i){ printf("%d\n",ret[i]); } }

上面代码中 MAXN = 250000+7 时返回 WA 

~~~~(>_<)~~~~

To be continued ... ...

后缀自动机

标签:end   top   pre   接受   gets   style   struct   else   多少   

原文地址:http://www.cnblogs.com/Forgenvueory/p/7302483.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!