网上的题解都是后缀数组,我来个后缀自动机题解。

建好后缀自动机后由于后缀自动机是单向的,那么dfs一遍记录各节点的size,要保证一个节点只经过一次才是O(n),否则是O(n^2)。表示这个节点及后面还有几个节点。然后再来个ans数组,再dfs一次。这次如果走的是题目要的字母(记c),那么ans[x]+=siz[to],因为to能到的节点对应的子串都有c。如果走的不是c,那么ans[x]+=ans[to]。ans其实就表示该节点以后能有几个能有c的子串。同样ans只能走一次,否则是n^2的。那么开始时memset为-1。走到一个节点就赋为0。这样-1的点就是还需要dfs的,一个点只走一次。具体看两个dfs函数。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <cstring>
#include <map>
#include <queue>
#include <set>
#include <cassert>
#include <stack>
#include <bitset>
#define mkp make_pair
using namespace std;
const double EPS=1e-;
typedef long long lon;
const lon SZ=,SSZ=*SZ,APB=,INF=0x7FFFFFFF,mod=;
lon cnt,maxlen[SSZ],minlen[SSZ],nex[SSZ][APB];
lon slink[SSZ],siz[SSZ],ans[SSZ];
char dst,ch[SZ]; lon add(lon pre,lon c)
{
lon z=++cnt;
maxlen[z]=maxlen[pre]+;
lon u=pre;
for(;u!=-&&!nex[u][c];u=slink[u])
{
nex[u][c]=z;
}
if(u==-)
{
slink[z]=;
minlen[z]=;
}
else
{
lon x=nex[u][c];
if(maxlen[x]==maxlen[u]+)
{
slink[z]=x;
minlen[z]=maxlen[slink[z]]+;
}
else
{
lon v=++cnt;
memcpy(nex[v],nex[x],sizeof(nex[x]));
slink[v]=slink[x];
maxlen[v]=maxlen[u]+;
minlen[v]=maxlen[slink[v]]+;
slink[x]=slink[z]=v;
minlen[x]=maxlen[slink[x]]+;
minlen[z]=maxlen[slink[z]]+;
for(;u!=-&&nex[u][c]==x;u=slink[u])
{
nex[u][c]=v;
}
}
}
return z;
} void init()
{
scanf(" %c",&dst);
scanf(" %s",ch+);
lon pre=;
slink[]=-;
cnt=;
memset(ans,-,sizeof(ans));
for(lon i=;ch[i];++i)
{
pre=add(pre,ch[i]-'a');
}
} void dfs1(lon x)
{
siz[x]=;
for(lon i=;i<APB;++i)
{
lon t=nex[x][i];
if(t)
{
if(!siz[t])dfs1(t);
siz[x]+=siz[t];
}
}
} void dfs2(lon x)
{
ans[x]=;
for(lon i=;i<APB;++i)
{
lon t=nex[x][i];
if(t)
{
if(ans[t]==-)dfs2(t);
if(i==dst-'a')ans[x]+=siz[t];
else ans[x]+=ans[t];
}
}
} void work()
{
dfs1();
dfs2();
cout<<ans[]<<endl;
for(int i=;i<=cnt;++i)
{
memset(nex[i],,sizeof(nex[i]));
siz[i]=;
}
} int main()
{
//std::ios::sync_with_stdio(0);
//freopen("d:\\1.txt","r",stdin);
lon casenum;
cin>>casenum;
//cout<<casenum<<endl;
for(lon time=;time<=casenum;++time)
//for(lon time=1;cin>>n>>len>>wid;++time)
{
cout<<"Case #"<<time<<": ";
init();
work();
}
return ;
}

hdoj5769后缀自动机版本的更多相关文章

  1. 后缀自动机(SAM)学习笔记

    目录 定义 SAM 的状态集 一些性质 SAM 的后缀链接 SAM 的转移函数 一些性质 算法构造 构造方法 时间复杂度证明 状态的数量 转移的数量 代码实现 实际应用 统计本质不同的子串个数 计算任 ...

  2. SPOJ8093Sevenk Love Oimaster(广义后缀自动机)

    Oimaster and sevenk love each other.     But recently,sevenk heard that a girl named ChuYuXun was da ...

  3. 后缀自动机SAM BZOJ 2806

    终于遇到了一道后缀数组不能过 一定要学SAM的题... (看了半个下午+半个上午) 现在总结一下(是给我自己总结..所以只总结了我觉得重要的 .. 看不太懂的话可以To   http://blog.c ...

  4. CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)

    What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...

  5. 【洛谷4482】Border的四种求法(后缀自动机_线段树合并_链分治)

    这题我写了一天后交了一发就过了我好兴奋啊啊啊啊啊啊 题目 洛谷 4482 分析 这题明明可以在线做的,为什么我见到的所有题解都是离线啊 -- 什么时候有机会出一个在线版本坑人. 题目的要求可以转化为求 ...

  6. 一文读懂后缀自动机 Suffix_Automata

    原论文(俄文)地址:suffix_automata 原翻译(中文)地址:后缀自动机详解(DZYO的博客) Upd:强推浅显易懂(?)的SAM讲解 后缀自动机 后缀自动机(单词的有向无环图)--是一种强 ...

  7. 『后缀自动机入门 SuffixAutomaton』

    本文的图片材料多数来自\(\mathrm{hihocoder}\)中详尽的\(SAM\)介绍,文字总结为原创内容. 确定性有限状态自动机 DFA 首先我们要定义确定性有限状态自动机\(\mathrm{ ...

  8. 后缀自动机(SAM)奶妈式教程

    后缀自动机(SAM) 为了方便,我们做出如下约定: "后缀自动机" (Suffix Automaton) 在后文中简称为 SAM . 记 \(|S|\) 为字符串 \(S\) 的长 ...

  9. BZOJ 后缀自动机四·重复旋律7

    后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的 ...

随机推荐

  1. findStr

    目录 规则 目录结构 src/main.cpp src/findstr.cpp include/findstr.h ft/TestCase.cpp ft/makefile ftbuild.sh mai ...

  2. 记录常用的adb命令

    1.启动adb服务 adb start-server 2.关闭服务 adb kill-server 3.进入shell环境 adb shell 4.安装应用 adb install -r xxx.ap ...

  3. GIL学习

    GIL锁 一.GIL的简单概述 二.GIL对于多线程的影响 三.解决GIL对于多线程影响的方案 回到顶部 一.GIL的简单概述 1.概念 GIL ( Global Interperter Lock ) ...

  4. 图片居中table-cell

  5. java Quartz定时器任务与Spring 的实现

    1.xml配置 <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http:/ ...

  6. js实现多行文本溢出省略

    实现效果: css: position: relative; line-height: 20px; max-height: 60px; js: function overflowHiddon(el) ...

  7. 记使用talend从oracle抽取数据时,数字变为0的问题

    数据源为oracle,字段类型为number. 发现通过mainline连接到一个logrow控件,输入的该字段的值为0 经过多次测试还是没发现有什么规律. 通过查看代码发现有这一句内容. if (r ...

  8. PHP 批量操作删除,支持单个删除

    PHP  执行部分: <?php include('checkadmin.php'); header('Content-Type: text/html; charset=utf-8'); if( ...

  9. html5 javascript 新增加的高级选择器更精准更实用

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  10. win10忘记开机密码无法进入桌面

    第一种: 电脑用微软账户登录,但密码始终不正确. 登陆这个网址    https://account.live.com/password/reset 按照提示的操作利用之前注册信息一步步重设密码 最后 ...