【bzoj3926】 Zjoi2015—诸神眷顾的幻想乡
http://www.lydsy.com/JudgeOnline/problem.php?id=3926 (题目链接)
题意
给出一棵树,每个节点有一个编号,范围在${[0,9]}$。一个序列是指树上某条路径上的点的编号按顺序依次相接连成的字符串。问有多少个不同的序列。
Solution
广义后缀自动机,看起来好高深的样子,然而题解却很简单。这道题好像只是一个很简单的应用吧。
首先题目数据范围有一个很特殊的地方:叶子节点数${<=20}$。嘿嘿嘿,这就可以搞事情了。
我们往叶子节点上想,慢慢就会发现一个结论:任意一个存在的序列都可以以某个叶子节点为根进行dfs得到。
所以,我们对于每个叶子节点建立一个${trie}$树,将这些${trie}$树构成一个广义后缀自动机,最后在后缀自动机中扫一遍每一个状态,它所贡献的不同序列个数就是它的${len}$减父亲的${len}$。
下面引用一段广义后缀自动机的介绍,来自:http://blog.csdn.net/wangzhen_yu/article/details/45481269
广义后缀自动机:
传统后缀自动机是解决单个主串的匹配问题,广义后缀自动机可以用来解决多个主串的匹配问题,这样我们就不用把所有主串接在一起构造自动机了,大大节省了时间空间。
如何将多个主串构建成广义后缀自动机?先将一个主串建立成后缀自动机,然后将重置last,令last=root,下一个字符串再从头节点开始建立,下一状态如果不存在,则以后缀自动机的规则进行建立新节点。
如果下一状态已经建立,我们直接转移到该状态即可,既然到达该状态,说明已经匹配成功的字符串的所有后缀都在该状态及该状态的父节点,父节点的父节点...直到root,所以我们需要对该状态以及他的父节点,他的父节点的父节点。。。直到root进行内容更新,更新的内容当然因题目而异,如果求某个字符串出现的个数,就cnt++,如果求某个字符串出现的位置,就将位置存在结点的一个数组里。
细节
因为是广义后缀自动机,注意数组大小。答案开LL。
代码
// bzoj3926
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define RG register
#define LL long long
#define inf (1ll<<30)
#define MOD 1000000007
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=2000010;
int ch[maxn<<1][10],par[maxn<<1],len[maxn<<1],Dargen,sz;
int head[maxn],deg[maxn],a[maxn],n,C,cnt; struct edge {int to,next;}e[maxn<<1]; void link(int u,int v) {
e[++cnt]=(edge){v,head[u]};head[u]=cnt;
e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
int Extend(int c,int p) {
int np=++sz;
len[np]=len[p]+1;
for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;
if (!p) par[np]=Dargen;
else {
int q=ch[p][c];
if (len[q]==len[p]+1) par[np]=q;
else {
int nq=++sz;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
par[nq]=par[q];
par[np]=par[q]=nq;
for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
}
}
return np;
}
void dfs(int x,int fa,int p) {
int t=Extend(a[x],p);
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) dfs(e[i].to,x,t);
}
int main() {
scanf("%d%d",&n,&C);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int u,v,i=1;i<n;i++) {
scanf("%d%d",&u,&v);
link(u,v);deg[u]++;deg[v]++;
}
Dargen=sz=1;
for (int i=1;i<=n;i++) if (deg[i]==1) dfs(i,0,1);
LL ans=0;
for (int i=1;i<=sz;i++) ans+=len[i]-len[par[i]];
printf("%lld",ans);
return 0;
}
【bzoj3926】 Zjoi2015—诸神眷顾的幻想乡的更多相关文章
- bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对[广义后缀自动机]的一些理解
先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存 ...
- BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 字符串 SAM
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3926.html 题目传送门 - BZOJ3926 题意 给定一个有 $n$ 个节点,最多只有 $20$ ...
- BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡(广义SAM)
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- [BZOJ3926][ZJOI2015]诸神眷顾的幻想乡(后缀自动机)
日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去 ...
- BZOJ3926 Zjoi2015 诸神眷顾的幻想乡【广义后缀自动机】
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 【广义后缀自动机】
题目 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴 ...
- BZOJ3926: [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- BZOJ3926 ZJOI2015诸神眷顾的幻想乡(广义后缀自动机)
对多串建立SAM的一种方法是建trie再对trie建SAM.构造方式分为在线(也即不建trie而是依次插入每个串,或在trie上dfs)和离线(也即建好trie再bfs).其中离线构造与单串的构造方式 ...
- bzoj3926: [Zjoi2015]诸神眷顾的幻想乡
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- BZOJ3926 ZJOI2015 诸神眷顾的幻想乡 Trie、广义SAM
传送门 树上的任意一条路径一定会在以某一个叶子节点为根的树上成为一条直上直下的链,而总共只有\(20\)个叶子节点. 于是每一次选所有叶子节点中的一个作为根,形成一个\(Trie\),把\(20\)个 ...
随机推荐
- 我看微软收购GitHub
今天是微软收购GitHub的第三天,之前很多人担心被微软收购的GitHub会步Skype,诺基亚等企业的后尘,凡此种种我觉得更多人的担心是:GitHub不再开源免费罢了. GitHub今年4月刚成立十 ...
- Netty源码分析第1章(Netty启动流程)---->第2节: NioServerSocketChannel的创建
Netty源码分析第一章: Server启动流程 第二节:NioServerSocketChannel的创建 我们如果熟悉Nio, 则对channel的概念则不会陌生, channel在相当于一个通 ...
- python 根据年月日,计算是这一年中的第几天
利用python计算某一天是这一年中的第几天,例如,给定年份= 2019年,月份= 1,日期= 3,则返回3:因为2019-01-03日期是2019年的第3 天. 首先,我们要知道闰年.平年怎么区分: ...
- Daily Scrum6 11.10
今日任务: 徐钧鸿:codingcook的sql相关内容,并在进行复查张艺:继续用户管理部分代码黄可嵩:学习搜索的知识,继续进行搜索的移植和响应徐方宇:动态控件和页面间信息传递以及页面响应事件机制试验 ...
- Scrum Meeting 11.05
成员 今日任务 明日计划 用时 徐越 代码移植 学习ListView+simpleAdapter,actionBar.阅读并修改前端代码 4h 赵庶宏 服务器配置,代码移植 构建后端数据库,进行完善 ...
- 每日Scrum(10)
今天我们小组整合了下我们所编辑的程序,然后在界面上进行了修改和少部分的完善,现在就等着下午的验收了 任务展板 燃尽图如下:
- 调研Android的开发环境的发展演变
在 知道要做基于移动端的项目实践时,我就选定了Android,回来的时候查了很多相关的知识,很多人都在问开发安卓软件,使用eclipse还是用 Android studio?其实,也没有一个准确的答案 ...
- ResNet笔记
参考: Deep Learning-TensorFlow (14) CNN卷积神经网络_深度残差网络 ResNet 先前的研究已经证明,拥有至少一个隐层的神经网络是一个通用的近似器,只要提高网络的深度 ...
- Unity如何判断网络状态?
根据Application.internetReachability来判断网络状态 NetworkReachability.NotReachable 网络不可用 NetworkReachability ...
- Ubuntu下tensorboard的使用
1. 找到运行程序的事件输出路径 找到路径并进入,例如我的是在路径/home/ly/codes下: 2. 打开tensorboard服务器 在终端输入(--logdir=自己所存的路径): t ...