【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\)个 ...
随机推荐
- SICP读书笔记 2.4
SICP CONCLUSION 让我们举起杯,祝福那些将他们的思想镶嵌在重重括号之间的Lisp程序员 ! 祝我能够突破层层代码,找到住在里计算机的神灵! 目录 1. 构造过程抽象 2. 构造数据抽象 ...
- shell小记
1.以#!/bin/bash 开头2.执行方式 bash sh ./ `script`3.变量: 系统变量 自定义变量 --->export 可导出为全局环境变量 set显示所 ...
- DockerCon2017前瞻 - Docker企业版体验
DockerCon 2017将于四月17号在美国Austin召开.在去年DockerCon上,Docker公司一系列的发布吹响了进军企业市场的号角.今天,容器技术已经愈发成熟,被越来越多的企业所关注和 ...
- shutdown命令详解
基础命令学习目录 原文链接:http://www.cnblogs.com/qlqwjy/p/7746364.html 我 们在操作Linux v/服务器的时候肯定会有需要重启系统,或者关闭系统等操作. ...
- ansible软件2
常用软件安装及使用目录 ansible使用1 第1章 copy模块 1.1 创建文件及写入内容 1. [root@m01 scripts]# ansible oldboy -m copy -a &q ...
- SpringBoot初始教程之Redis集中式Session管理
1.介绍 有关Session的管理方式这里就不再进行讨论,目前无非就是三种单机Session(基于单机内存,无法部署多台机器).基于Cookie(安全性差).基于全局的统一Session管理(redi ...
- Python基础_eval(),exec(),globals(),locals(),compile()
转发:http://www.cnblogs.com/yyds/p/6276746.html 1. eval函数 函数的作用: 计算指定表达式的值.也就是说它要执行的Python代码只能是单个运算表达式 ...
- Django之自带认证
自带登录实例 {% extends "layout/base.html" %} // 所有link {% block body %} <div id="contai ...
- linux后退文件夹命令
后退文件夹: cd - 在重复一遍就是前进了
- static和final
是静态修饰符,什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只 ...