博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities
阅读量:6836 次
发布时间:2019-06-26

本文共 4089 字,大约阅读时间需要 13 分钟。

  Palindromes and Super Abilities

Problem's Link:


 

Mean: 

给你一个长度为n的字符串S,输出S的各个前缀中回文串的数量。

analyse:

回文树(回文自动机)的模板题。

由于回文自动机中的p是一个计数器,也相当于一个指针,记录的是当前插入字符C后回文树中有多少个节点。

那么我们只需要一路插,一路输出p-2就行。

p-2是因为一开始回文树中就有两个节点。这是两个根节点,分别是长度为偶数和奇数的回文串的根节点。

 

Time complexity: O(N)

 

Source code: 

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-08-17-14.58
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using
namespace
std;
const
int
MAXN
=
100005 ;
const
int N
=
26 ;
char s
[
MAXN
];
namespace
Palindromic_Tree
{
     
int
next
[
MAXN
][N
] ;
//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
     
int
fail
[
MAXN
] ;
//fail指针,失配后跳转到fail指针指向的节点
     
int
cnt
[
MAXN
] ;
     
int
num
[
MAXN
] ;
     
int
len
[
MAXN
] ;
//len[i]表示节点i表示的回文串的长度
     
int S
[
MAXN
] ;
//存放添加的字符
     
int
last ;
//指向上一个字符所在的节点,方便下一次add
     
int n ;
//字符数组指针
     
int p ;
//节点指针
     
int
newnode(
int
l)    
//新建节点
     
{
           
for(
int
i
=
0 ;
i
< N ;
++
i)
next
[p
][
i
]
=
0 ;
           
cnt
[p
]
=
0 ;
           
num
[p
]
=
0 ;
           
len
[p
]
=
l ;
           
return p
++ ;
     
}
     
void
init()  
//初始化
     
{
           p
=
0 ;
           
newnode(
0) ;
           
newnode(
-
1) ;
           
last
=
0 ;
           n
=
0 ;
           S
[n
]
=
-
1 ;
//开头放一个字符集中没有的字符,减少特判
           
fail
[
0
]
=
1 ;
     
}
     
int
get_fail(
int
x)    
//和KMP一样,失配后找一个尽量最长的
     
{
           
while(S
[n
-
len
[
x
]
-
1
]
!= S
[n
])
x
=
fail
[
x
] ;
           
return
x ;
     
}
     
void
add(
int
c)
     
{
           
c
-=
'a' ;
           S
[
++ n
]
=
c ;
           
int
cur
=
get_fail(
last) ;  
//通过上一个回文串找这个回文串的匹配位置
           
if(
!
next
[
cur
][
c
])    
//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
           
{
                 
int
now
=
newnode(
len
[
cur
]
+
2) ;  
//新建节点
                 
fail
[
now
]
=
next
[
get_fail(
fail
[
cur
])][
c
] ;  
//和AC自动机一样建立fail指针,以便失配后跳转
                 
next
[
cur
][
c
]
=
now ;
                 
num
[
now
]
=
num
[
fail
[
now
]]
+
1 ;
           
}
           
last
=
next
[
cur
][
c
] ;
           
cnt
[
last
]
++ ;
     
}
     
void
Count()
     
{
           
for(
int
i
= p
-
1 ;
i
>=
0 ;
--
i)
cnt
[
fail
[
i
]]
+=
cnt
[
i
] ;
           
//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
     
}
} ;
using
namespace
Palindromic_Tree;
int
main()
{
     
ios_base
::
sync_with_stdio(
false);
     
cin
.
tie(
0);
     
while(
~
scanf(
"%s"
,s))
     
{
           
init();
           
for(
int
i
=
0;s
[
i
];
++
i)
           
{
                 
add(s
[
i
]);
                 
printf(
i
==
0
?
"%d"
:
" %d"
,p
-
2);
           
}
           
puts(
"");
//            Count();
     
}
     
return
0;
}
/*
*/

代码2:

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-08-17-16.51
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using
namespace
std;
const
int
MAXN
=
100010;
struct
node
{
     
int
next
[
26
];
     
int
len;
     
int
sufflink;
     
int
num;
};
int
len;
char s
[
MAXN
];
node
tree
[
MAXN
];
int
num;
// node 1 - root with len -1, node 2 - root with len 0
int
suff;
// max suffix palindrome
long
long
ans;
bool
addLetter(
int
pos)
{
     
int
cur
=
suff
,
curlen
=
0;
     
int
let
= s
[
pos
]
-
'a';
     
while(
true)
     
{
           
curlen
=
tree
[
cur
].
len;
           
if(
pos
-
1
-
curlen
>=
0
&&s
[
pos
-
1
-
curlen
]
==s
[
pos
])
break;
           
cur
=
tree
[
cur
].
sufflink;
     
}
     
if(
tree
[
cur
].
next
[
let
])
     
{
           
suff
=
tree
[
cur
].
next
[
let
];
           
return
false;
     
}
suff
=
++
num;
     
tree
[
num
].
len
=
tree
[
cur
].
len
+
2;
     
tree
[
cur
].
next
[
let
]
=
num;
     
if(
tree
[
num
].
len
==
1)
     
{
           
tree
[
num
].
sufflink
=
2;
           
tree
[
num
].
num
=
1;
           
return
true;
     
}
     
while(
true)
     
{
           
cur
=
tree
[
cur
].
sufflink;
           
curlen
=
tree
[
cur
].
len;
           
if(
pos
-
1
-
curlen
>=
0
&& s
[
pos
-
1
-
curlen
]
== s
[
pos
])
           
{
                 
tree
[
num
].
sufflink
=
tree
[
cur
].
next
[
let
];
                 
break;
           
}
     
}
     
tree
[
num
].
num
=
1
+
tree
[
tree
[
num
].
sufflink
].
num;
     
return
true;
}
void
initTree()
{
     
num
=
2;
suff
=
2;
     
tree
[
1
].
len
=
-
1;
tree
[
1
].
sufflink
=
1;
     
tree
[
2
].
len
=
0;
tree
[
2
].
sufflink
=
1;
}
int
main()
{
     
scanf(
"%s"
,s);
     
len
=
strlen(s);
     
initTree();
     
for(
int
i
=
0;
i
<
len;
i
++)
     
{
           
addLetter(
i);
           
printf(
i
==
0
?
"%d"
:
" %d"
,
num
-
2);
//            ans += tree[suff].num;
     
}
     
putchar(
10);
//       cout << ans << endl;
     
return
0;
}

 

转载地址:http://zqxkl.baihongyu.com/

你可能感兴趣的文章
HDU_3062 Party (2-SAT)
查看>>
dynamic_shift_reg SRL16E
查看>>
尝试用微博记录 SQL Server 2012开发者训练营笔记
查看>>
.Net中的5种事务总结
查看>>
为什么 Git 比 SVN 好
查看>>
关于Qt的MVC模型思想(转载)
查看>>
Vagrant支持Amazon AWS和Rackspace
查看>>
JNDI全攻略(二)(转)
查看>>
POJ1463:Strategic game(树形DP)
查看>>
SPOJ LCS(Longest Common Substring-后缀自动机-结点的Parent包含关系)
查看>>
Tuning 05 Sizing other SGA Structure
查看>>
用 Qt Creator 开发非 Qt 的 C/C++ 程序
查看>>
Android-Cannot merge new index 66195 into a non-jumbo instruction的解决的方法
查看>>
解决 com.sun.*包导入错误
查看>>
【WP 8.1开发】如何动态生成Gif动画
查看>>
C#零基础入门08:代码规范
查看>>
关于php的mysqlnd驱动
查看>>
Response
查看>>
人人都看得懂的正则表达式教程
查看>>
python matplotlib 绘图
查看>>