【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;
}
时间: 2024-10-07 12:12:27

【bzoj3926】 Zjoi2015—诸神眷顾的幻想乡的相关文章

BZOJ3926 ZJOI2015 诸神眷顾的幻想乡 后缀自动机+DFS

题意:给定一颗字符树,求树中路径所构成的不同的字符串的数量,其中AB和BA视作不同的字符串 题解: 题目里有这样一句话:太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过20个. 一共有10W个点,却只有20个叶子……因此树上所有的字串就是以叶子为起点搜索出的所有字串,丽洁姐真的好善良啊- -(无雾) 这样从每个点开始就能跑出来一颗Trie树,对Trie构造广义后缀自动机——每个节点看成是一个根,在后面加字符的时候和普通的SAM一样. 然后在SAM上用DFS统计不同字串的数量即可 #inc

bzoj3926: [Zjoi2015]诸神眷顾的幻想乡

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define maxn 100005 7 #define maxl 200005 8 #define maxm 4000005 9 using namespace std; 10 11 typedef long long ll; 12

[BZOJ3926] [ZJOI2015]诸神眷顾的幻想乡|后缀自动机

唔..过去了一个多月才敢动一下一试的题呢..毕竟好神啊好神啊 看右边→就写着Orz yu990601 那不如就从他A掉的T3开始吧... 昨天晚上看了一下SAM..大概还是比较亲切的吧 毕竟去年暑假还是听过的...虽然并没有听懂 但是很开心的是现在再看CLJ的讲稿的时候大部分都能看懂了呢 直接这道题吧...首先这棵树的叶子节点不超过20个 然后一个很神奇的性质就是所有的子串都会在以某个叶子节点为根的树上以一条直线的姿态出现... 这么说不利于解题...也就是必定会作为叶子节点到以它为根的树上的某

bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对广义后缀自动机的一些理解

先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存在,应当建立一个状态来表示这个串,显然,这个状态(np)的right集合是{L+1},max=L+1. 现在新建立了一个状态,我们还有两件事要干:找出能转移到这个状态的状态,建立链接:确定这个状态的min,即找到它在parent树上的父亲. 能转移到$np$的状态显然都是right集合包含L的状态,

bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 后缀自动机在tire树上拓展

题意:有棵树每个点有个颜色(不超过10种),每个节点不超过20个儿子,问你每两点之间的颜色序列不同的有多少种 题解:先建出树,对于每个叶子节点,bfs一遍建在sam上,每次保留当前点在sam上的位置,拓展时用父亲节点在sam上的位置当成last即可.然后统计sam本质不同的字符串有多少个 注:dfs建树复杂度是错的,但是也能过这题 /************************************************************** Problem: 3926 User:

【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机

[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来.也就是说,这n块空地形成了一个树的结构. 有n个粉丝们来到了太阳花田上.为了表达对幽香生日的祝

[Zjoi2015]诸神眷顾的幻想乡

[Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1537  Solved: 892 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建了n-1条

字符串(广义后缀自动机):BZOJ 3926 [Zjoi2015]诸神眷顾的幻想乡

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 843  Solved: 510[Submit][Status][Discuss] Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n

BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1017  Solved: 599[Submit][Status][Discuss] Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有

【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 974  Solved: 573 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建