[BZOJ3238]-[Ahoi2013]差异-后缀自动姬
2018-01-18 12:28
393 查看
说在前面
感觉后缀自动姬真好玩hhhhh今天分配任务,me要去讲小专题,然而感觉自己就没有什么专精的东西啊!
果然me还是太弱了
题目
BZOJ3238传送门题面
输入输出格式
输入格式:输入仅一行,包含一个字符串
输出格式:
当然是输出答案啦
解法
这题要用到一点parent树的性质,不过很简单YY一下就知道的parent树实质上就是这个字符串的反前缀树,怎么理解呢,right集合就是右端点位置的集合,随着向左延伸的长度不断变长,right集合不断分裂,分裂到最后每个right集合都只有一个元素,这个元素就是原串的一个前缀。所以,如果把一个串倒过来建后缀自动姬,它的parent树实际上就是后缀树
那么对于这道题,前面的部分可以O(1)求,关键就是求各个后缀的最长公共前缀,然后这正好就是后缀树干的事情。于是我们对反串建立后缀自动姬,处理出parent树,然后dfs一遍parent树,每个节点的贡献就是它的各个儿子的 叶子节点个数 的乘积。于是这道题就做完了。
下面是自带大常数的代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; char ss[500005] ; int N , id_c , head[1000005] , tp ; long long ans ; struct Node{ char cc ; int len , id , siz ; Node *ch[26], *par ; }w[1000005] , *tw = w , *root , *last ; struct Path{ int pre , to ; }p[1000005] ; void In( const int &t1 , const int &t2 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ; } void newNode( Node *&nd , char cc , int len ){ nd = ++tw ; nd->siz = 1 ; nd->id = ++id_c , nd->cc = cc ; nd->len = len ; } void Insert( const char &cc ){ Node *nd , *tmp = last ; newNode( nd , cc , last->len + 1 ) ; short id = cc - 'a' ; for( ; tmp && !tmp->ch[id] ; tmp = tmp->par ) tmp->ch[id] = nd ; if( !tmp ) nd->par = root ; else{ if( tmp->ch[id]->len == tmp->len + 1 ) nd->par = tmp->ch[id] ; else{ Node *B = tmp->ch[id] , *nB = ++ tw ; *nB = *B ; nB->siz = 0 ; nB->id = ++id_c , nB->len = tmp->len + 1 ; //Notice!!! 需要分配id B->par = nd->par = nB ; while( tmp && tmp->ch[id] == B ){ tmp->ch[id] = nB ; tmp = tmp->par ; } } } last = nd ; } long long dfs( int u ){ long long siz = w[u].siz , tmp ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; tmp = dfs( v ) ; ans -= siz * tmp * w[u].len * 2 ; siz += tmp ; } return siz ; } void solve(){ ans = 1LL * ( N - 1 ) * ( N + 1 ) * N / 2 ; for( Node *t = w + 1 ; t <= tw ; t ++ ) if( t->par ) In( t->par->id , t->id ) ; for( int i = head[ root->id ] ; i ; i = p[i].pre ) dfs( p[i].to ) ; printf( "%lld" , ans ) ; } int main(){ scanf( "%s" , ss + 1 ) ; N = strlen( ss + 1 ) ; newNode( root , 0 , 0 ) ; last = root ; for( int i = N ; i >= 1 ; i -- ) Insert( ss[i] ) ; solve() ; }
相关文章推荐
- [BZOJ3238] [AHOI2013] 差异 - 后缀自动机
- BZOJ 3238 [Ahoi2013] 差异 | 后缀数组 单调栈
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
- BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp
- BZOJ_3238_[Ahoi2013]差异_后缀自动机
- BZOJ 3238 AHOI2013 差异 后缀自动机
- 【BZOJ 3238】[Ahoi2013]差异 后缀自动机构造后缀树
- BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]
- bzoj 3238: [Ahoi2013]差异 后缀数组
- bzoj3238 [Ahoi2013]差异 后缀自动机
- bzoj 3238: [Ahoi2013]差异 -- 后缀数组
- [BZOJ3238][Ahoi2013][后缀自动机][树形DP]差异
- BZOJ 3238: [Ahoi2013]差异|后缀数组|乘法原理
- bzoj 3238 [Ahoi2013]差异 后缀数组 并查集
- bzoj 3238: [Ahoi2013]差异 后缀自动机
- 后缀数组+单调栈 【Ahoi2013】bzoj3238 差异
- [BZOJ3238][Ahoi2013]差异(后缀自动机||后缀数组)
- [后缀自动机][树形DP] BZOJ 3238: [Ahoi2013]差异
- [Ahoi2013]差异 bzoj 3238 后缀自动机
- bzoj 3238: [Ahoi2013]差异 (后缀自动机+树形dp)