BZOJ 3238 AHOI2013 差异 后缀自动机

题目大意:给定一个字符串,求Σ[1<=i<j<=n]|Ti|+|Tj|-2|LCP(Ti,Tj)|

前两项是可以O(1)求的 我们要求的就是LCP之和

对反串建立后缀自动机 那么parent指针连成的树就是后缀树

直接在后缀树上DP就行- -

对于每个节点统计所有子树两两right集合大小乘积之和乘上这个节点的深度即可

QY神在学校讲了一天的SAM。。。 现在我觉得我还是回去学大型建筑机械吧233- -

#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 500500
using namespace std;
namespace Suffix_Automaton{
	struct SAM{
		map<int,SAM*> son;
		vector<SAM*> tree_son;
		SAM *parent;
		int max_dpt,right;
		bool mark;
		SAM(int _):parent(0x0),max_dpt(_),right(0),mark(false) {}
	}*root=new SAM(0),*last=root;
	void Extend(int x)
	{
		SAM *p=last;
		SAM *np=new SAM(p->max_dpt+1);
		for(;p&&!p->son[x];p=p->parent)
			p->son[x]=np;
		if(!p) np->parent=root;
		else
		{
			SAM *q=p->son[x];
			if(p->max_dpt+1==q->max_dpt)
				np->parent=q;
			else
			{
				SAM *nq=new SAM(p->max_dpt+1);
				nq->son=q->son;
				nq->parent=q->parent;
				q->parent=nq;np->parent=nq;
				for(;p&&p->son[x]==q;p=p->parent)
					p->son[x]=nq;
			}
		}
		last=np;
		np->right++;
	}
}
int n;
long long ans;
char s[M];
void DFS(Suffix_Automaton::SAM *p)
{
	using namespace Suffix_Automaton;
	map<int,SAM*>::iterator it;
	if(p->parent)
		p->parent->tree_son.push_back(p);
	p->mark=1;
	for(it=p->son.begin();it!=p->son.end();it++)
		if( !(it->second)->mark )
			DFS(it->second);
}
void Tree_DP(Suffix_Automaton::SAM *p)
{
	using namespace Suffix_Automaton;
	vector<SAM*>::iterator it;
	for(it=p->tree_son.begin();it!=p->tree_son.end();it++)
	{
		Tree_DP(*it);
		ans-=(long long)p->max_dpt*p->right*(*it)->right<<1;
		p->right+=(*it)->right;
	}
}
int main()
{
	using namespace Suffix_Automaton;
	int i;
	scanf("%s",s+1);n=strlen(s+1);
	for(i=n;i;i--)
		Extend(s[i]-'a');
	ans=(long long)(n-1)*n*(n+1)/2;
	DFS(root);Tree_DP(root);
	cout<<ans<<endl;
	return 0;
}
时间: 2024-12-11 16:07:10

BZOJ 3238 AHOI2013 差异 后缀自动机的相关文章

BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有两幅面孔呢). 看代码实现吧,不大容易口头解释,把加的和减的分开算就可以了,减去的通过倒着建sam(相当于建一棵后缀树),然后算每个len取的次数实现,注意树归中一些避免重复操作. 1 /********************************************************

bzoj 3238: [Ahoi2013]差异 -- 后缀数组

3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 Source 后缀数组+单调栈水过... #include<map> #include<cmath> #include<

bzoj 3238 [Ahoi2013]差异 后缀数组 + 单调栈

题目链接 Description 一个长度为\(n\)的字符串\(S\),令\(T_i\)表示它从第\(i\)个字符开始的后缀.求\[\sum_{1\leq i\leq j\leq n}len(T_i)+len(T_j)-2*lcp(T_i,T_j)\]其中,\(len(a)\)表示字符串\(a\)的长度,\(lcp(a,b)\)表示字符串\(a\)和字符串\(b\)的最长公共前缀. \(2\leq n\leq 500000\) 思路 \(O(n^2)\)枚举显然是不可行的,应从 贡献 的角度取

【BZOJ 3238】差异 后缀自动机+树形DP

题意 给定字符串,令$s_i$表示第$i$位开始的后缀,求$\sum_{1\le i < j \le n} len(s_i)+len(s_j)-2\times lcp(s_i,s_j)$ 先考虑前面的和式,直接计算为$\frac{n(n^2-1)}{2}$,考虑后面的和式,$lcp$相关可以用sam求解,sam形成的parent树是原串的前缀树,所以两个串的最长公共后缀是在parent树上最近公共祖先对应的状态的长度$maxlen_s-maxlen_{pa_s}$,将原串反向建立sam得到后缀树

BZOJ 3238 [Ahoi2013]差异(后缀自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个串,设T[i]表示从第i位开始的后缀, 求sum(len(T[i])+len(T[j])-2*lcp(T[i],T[j])) [题解] 根据反串的后缀自动机建立后缀树, 则两点的LCA在自动机中的length就是他们的LCP, 树形DP统计一下即可. [代码] #include <cstdio> #include <algorithm> #i

●BZOJ 3238 [Ahoi2013]差异

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3238 题解: 后缀数组套路深. 问题转化为求出任意两个后缀的LCP之和 在计算贡献时,各种不爽,然后就套路的从height[i]数组下手.计算出 L[i]和 R[i],L[i]:找出排名最小(即为 L[i])的后缀与排名为 i的后缀的 LCP==hei[i]R[i]:找出排名最大(即为 R[i])的后缀与排名为 i的后缀的 LCP==hei[i](更直白一点就是在hei数组中找出最大的包含

bzoj 3238: [Ahoi2013]差异

一看字符串 最长公共前缀,用后缀数组+单调栈搞搞就行啦.一定要注意long long 啊 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #de

bzoj 3238: [Ahoi2013]差异【SAM+树形dp】

首先只有lcp(i,j)需要考虑 因为SAM的parent树是后缀的前缀的最长公共后缀(--),所以把这个串倒过来建SAM,这样就变成了求两个前缀的最长公共后缀,长度就是这两个前缀在parent树上的lcs对应的最大长度dis 这里用treedp解决即可,就是合并一下size #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace st

【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)

3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3047  Solved: 1375 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 Source [分析] 这题先把sigma len 加上. 然后考虑一下减掉的是什么. 对于每个子