您的位置:首页 > 其它

UVALIVE 5792 Trie+统计

2013-09-27 21:58 387 查看
题意:给你两种串,一种可以当前缀,一种可以当后缀,问两种串合起来,一共有多少种组合。并且没有重合。

思路:我们先将两种串插入字典树,对于后缀串,我们反向插入,然后处理出每个字符对应的后缀的个数。

我们来看一个组合的串,c = a + b 。这个c可能很多种组合,但是,只要我们取a最大,那么这样计数就是唯一的。所谓a最大就是当搜到a是该前缀的最后一个字母,那么a就是最大的。

这是对应a是最后一个字母的情况,那么如果a后面还有字母呢,那么我们可以找是否存在一个后缀,他只有一个字母,那么我们可以把他接到a的后面。

所以对应的一个前缀a,我们只要分这两种情况考虑即可。

注意是使用long long 。

#define N 311111
ll ans = 0 ;
ll sum[30] ;
int end[30] ;
struct TT {
int num ;
int T
[26] ;

TT() {
num = 0 ;
}
void INIT() {
mem(T[0], -1) ;
num = 0 ;
}
void init(int x) {
mem(T[x] , -1) ;
}
void insert(char *s) {
int l = strlen(s) ;
int now = 0 ;
for (int i = 0 ; i < l ; i ++ ) {
int a = s[i] - 'a' ;
if(T[now][a] == -1) {
T[now][a] = ++ num ;
init(num) ;
}
now = T[now][a] ;
}
}
void cal(int now) {
for (int i = 0 ; i < 26 ; i ++ ) {
if(T[now][i] == -1) {
ans += sum[i] ;
} else {
if(end[i])
ans ++ ;
cal(T[now][i]) ;
}
}
}
int fk(int now) {
for (int i = 0 ; i < 26 ; i ++ ) {
if(T[now][i] != -1) {
sum[i] ++ ;
fk(T[now][i]) ;
}
}
}
} sufTree , preTree ;

char s[1111] , p[1111] ;
int P , S ;
int main() {
while(cin >> P >> S, (P + S)) {
sufTree.INIT() ;
preTree.INIT() ;
for (int i = 0 ; i < P ; i ++ ) {
scanf("%s",p) ;
preTree.insert(p) ;
}
for (int i = 0 ; i < S ; i ++ ) {
scanf("%s",s) ;int l = strlen(s) ;
reverse(s , s + l) ;
sufTree.insert(s) ;
}
mem(sum , 0) ;
mem(end , 0) ;
ans = 0 ;
sufTree.fk(0) ;
for (int i = 0 ; i < 26 ; i ++ )if(sufTree.T[0][i] != -1)end[i] = 1 ;
for (int i = 0 ; i < 26 ; i ++ )if(preTree.T[0][i] != -1)preTree.cal(preTree.T[0][i]) ;
printf("%lld\n",ans) ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: