人生第一道后缀自动机,总是值得纪念的嘛。。

后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边。许多铺垫的理论似懂非懂。然后看了下自动机的构造发现代码倒是挺简单,但是理解原理却是十分的困难,最后在网上找到一篇带例子的讲解帖子,我感觉算是能够说服我的吧放个链接:

http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html

本题也是CLJ论文里的题,关键是如何求right集的大小,这里的求right集的大小我给个个人的理解,首先是按拓扑序吧,那三行for就有点像基数排序的姿势了,然后再由val大的算val小的。一开始令right++,是沿着root往下走的right 的初始大小,然后再按拓扑序往pre上加,就可以统计出每个状态的right集的大小了,姿势大致如此吧,代码完全参考了CLJ的论文和下面的这个链接:

http://blog.csdn.net/acm_cxlove/article/details/8222728

很感谢各位大神的分享,让我能够对后缀自动机有更深入的理解。

#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#define maxn 250050
using namespace std; struct State{
State *suf, *go[26];
int val, right;
State() :suf(0), val(0){
memset(go, 0, sizeof(go));
}
}*root,*last; State statePool[maxn * 2], *cur; void init()
{
cur = statePool;
root = last = cur++;
} void extend(int w)
{
State *p = last, *np = cur++;
np->val = p->val + 1;
while (p&&!p->go[w]) p->go[w] = np, p = p->suf;
if (!p) np->suf = root;
else{
State *q = p->go[w];
if (p->val + 1 == q->val){
np->suf = q;
}
else{
State *nq = cur++;
memcpy(nq->go, q->go, sizeof q->go);
nq->val = p->val + 1;
nq->suf = q->suf;
q->suf = nq;
np->suf = nq;
while (p&&p->go[w] == q){
p->go[w] = nq, p = p->suf;
}
}
}
last = np;
} char str[maxn + 50];
int n;
int tot;
int dp[maxn + 50];
int cnt[maxn + 50];
State *b[2 * maxn]; int main()
{
while (~scanf("%s", str))
{
init();
n = strlen(str);
for (int i = 0; i < n; i++){
extend(str[i] - 'a');
}
tot = cur - statePool;
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < tot; i++) cnt[statePool[i].val]++;
for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1];
for (int i = 0; i < tot; i++) b[--cnt[statePool[i].val]] = &statePool[i];
for (int i = 0; i < n; i++) {
root = root->go[str[i] - 'a']; root->right++;
}
memset(dp, 0, sizeof(dp));
for (int i = tot - 1; i > 0; i--){
dp[b[i]->val] = max(dp[b[i]->val], b[i]->right);
if (b[i]->suf) b[i]->suf->right += b[i]->right;
}
for (int i = n - 1; i >= 1; i--) dp[i] = max(dp[i], dp[i + 1]);
for (int i = 1; i <= n; i++) printf("%d\n", dp[i]);
}
return 0;
}

SPOJ NSUBSTR Substrings 后缀自动机的更多相关文章

  1. SPOJ NSUBSTR Substrings ——后缀自动机

    建后缀自动机 然后统计次数,只需要算出right集合的大小即可, 然后更新f[l[i]]和rit[i]取个max 然后根据rit集合短的一定包含长的的性质,从后往前更新一遍即可 #include &l ...

  2. ●SPOJ 8222 NSUBSTR–Substrings(后缀自动机)

    题链: http://www.spoj.com/problems/NSUBSTR/ 题解: 后缀自动机的水好深啊!懂不了相关证明,带着结论把这个题做了.看来这滩深水要以后再来了. 本题要用到一个叫 R ...

  3. Substrings SPOJ - NSUBSTR (后缀自动机)

    Substrings \[ Time Limit: 100ms\quad Memory Limit: 1572864 kB \] 题意 给出一个长度为 \(250000\) 的字符串,求出所有 \(x ...

  4. spoj 8222 Substrings (后缀自动机)

    spoj 8222 Substrings 题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.求F(1)..F(Length(S)) 解题思路:我们构造S的SAM,那么对于 ...

  5. SPOJ8222 NSUBSTR - Substrings(后缀自动机)

    You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as ...

  6. SPOJ8222 NSUBSTR - Substrings 后缀自动机_动态规划

    讲起来不是特别好讲.总之,如果 $dp[i+1]>=dp[i]$,故$dp[i]=max(dp[i],dp[i+1])$ Code: #include <cstdio> #inclu ...

  7. SP8222 NSUBSTR - Substrings(后缀自动机+dp)

    传送门 解题思路 首先建出\(sam\),然后把\(siz\)集合通过拓扑排序算出来.对于每个点只更新它的\(maxlen\),然后再从大到小\(dp\)一次就行了.因为\(f[maxlen-1]&g ...

  8. spoj 1812 lcsII (后缀自动机)

    spoj 1812 lcsII (后缀自动机) 题意:求多个串的lcs,最多10个串,每个串最长10w 解题思路:后缀自动机.先建好第一个串的sam,然后后面的串拿上去跑(这个过程同前一题).sam上 ...

  9. POJ.2774.Long Long Message/SPOJ.1811.LCS(后缀自动机)

    题目链接 POJ2774 SPOJ1811 LCS - Longest Common Substring 确实比后缀数组快多了(废话→_→). \(Description\) 求两个字符串最长公共子串 ...

随机推荐

  1. HashMap 读后感

    HashMap是一个哈希表,内部通过链地址法解决哈希冲突.内部用Entry数组保存数据,每个Entry是一个单向链表. HashMap不保证插入的顺序,线程不同步,允许null 下面是几个重要点: 保 ...

  2. C++将类的构造函数、析构函数声明为private或者protected的用途

    如果将构造函数.析构函数声明为private或者protected,表示不能从类的外部正常调用构造和析构函数了. 这种用法的通常使用的场景如下: 1.如果不想让外面的用户直接构造一个类A的对象,而希望 ...

  3. Cllimbing Stairs [LeetCode 70]

    1- 问题描述 You are climbing a stair case. It takes n steps to reach to the top. Each time you can eithe ...

  4. U-Boot--配置过程分析

    arm核:arm920t    2410 uboot版本:u-boot1.1.6 通过readme可以知道配置执行make smdk2410_config命令. 顶层Makefile : smdk24 ...

  5. linux 定时执行任务 crontab

    欲编写定时任务访问网页和打开图片 原来写法为 #!/bin/bash #可以执行 echoecho "Hello" > dir/file.txt #不可以执行 xdg-ope ...

  6. nginx总结

    kill int 2333  进程号   停止程序 kiil quit 2322  优雅停止服务 kill -HUP 2333  优雅重启 从新读取配置文件 kill -HUP 'cat logs/n ...

  7. Cassandra1.2文档学习解读计划——为自己鼓劲

    最近想深入研究一下Cassandra,而Cassandra没有中文文档,仅有的一些参考书都是0.7/0.6版本的.因此有个计划,一边学习文档(地址:http://www.datastax.com/do ...

  8. Android listview viewpager解决冲突 滑动

    Android listview viewpager滑动 跳动 冲突解决 ListView中嵌套ViewPage有或者滑动手势冲突解决   在listview 上使用 addHeaderView 在第 ...

  9. jQuery实现用户注册的表单验证

    用户注册的表单往往是需要进行验证的,否则会有一些不否合规则的数据入库,后果会不堪设想,本文通过jquery来实现. <html>  <head>  <meta chars ...

  10. Sublime Text 前端开发常用扩展插件推荐

    Sublime Text 前端开发常用扩展插件推荐 Sublime Text Sublime Text 是程序员们公认的编码神奇,拥有漂亮的用户界面和强大的功能 更重要的是,Sublime Text ...