【题解】POJ-3376 Finding Palindromes

Finding Palindromes(POJ-3376)

题面

A word is called a palindrome if we read from right to left is as same as we read from left to right. For example, “dad”, “eye” and “racecar” are all palindromes, but “odd”, “see” and “orange” are not palindromes.

Given n strings, you can generate n × n pairs of them and concatenate the pairs into single words. The task is to count how many of the so generated words are palindromes.

输入

The first line of input file contains the number of strings n. The following n lines describe each string:

The i+1-th line contains the length of the i-th string li, then a single space and a string of li small letters of English alphabet.

You can assume that the total length of all strings will not exceed 2,000,000. Two strings in different line may be the same.

输出

Print out only one integer, the number of palindromes.

样例输入

1
2
3
4
3
1 a
2 ab
2 ba

样例输出

1
5

提示

The 5 palindromes are:
aa aba aba abba baab

思路

把所有正串都加进一棵Trie,然后用每个串的逆串去跑Trie,此时会出现以下情况:

  1. 匹配完成,那么就说明存在一个正串的前缀是这个逆串。如果剩余的逆串回文,那么能形成回文。
  2. 匹配失败,Trie未结束,说明不能构成回文。
  3. Trie已经跑到叶子节点,匹配未结束,那么如果正串剩余部分回文,那么能形成回文。

用扩展KMP处理出一个串的每个后缀是不是回文串,方法是用该串和其逆串仅用扩展KMP匹配,如果ex[i]=(从i到末尾的长度),那么说明从i到末尾的后缀是回文的。

代码

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
char s[mxn], t[mxn], rev[mxn];
int nxt[mxn], extend[mxn];
int tree[mxn][26], exist[mxn], cnt = 0;
int len[mxn], val[mxn];
LL ans = 0;

void getnxt(char* t, int m)
{
int a, p; nxt[0] = m;
for (int i=1, j=-1; i<m; i++, j--)
{
if (j<0 || i+nxt[i-a] >= p)
{
if (j<0) p = i, j = 0;
while (p<m && t[p]==t[j]) p++, j++;
nxt[i] = j, a = i;
} else
nxt[i] = nxt[i-a];
}
}

void exKMP(char* s, char* t, int n, int m)
{
int a, p;
for (int i=0, j=-1; i<n; i++, j--) //j即等于p与i的距离,其作用是判断i是否大于p(如果j<0,则i大于p)
{
if (j<0 || i+nxt[i-a] >= p)
{
if (j<0) p = i, j = 0; //如果i大于p
while (p<n && j<m && s[p]==t[j]) p++, j++;
extend[i] = j, a = i;
} else
extend[i] = nxt[i-a];
}
}

void insert(char *s, int n)
{
int p = 0;
for (int i=0; i<n; i++)
{
int c = s[i] - 'a';
if (!tree[p][c]) tree[p][c] = ++cnt;
p = tree[p][c];
val[p] += (i+1<n && extend[i+1]==n-i-1) ? 1 : 0;
}
exist[p]++;
}

int search(char *s, int n)
{
int p = 0;
for (int i=0; i<n; i++)
{
int c = s[i] - 'a';
if (!tree[p][c]) return 0;
p = tree[p][c];
ans += (exist[p] && (i+1>=n || extend[i+1]==n-i-1)) ? exist[p] : 0;
}
ans += val[p];
return exist[p];
}

int main()
{
int n; scanf("%d", &n);
int st = 0;
for(int i=0; i<n; i++){
scanf("%d %s", &len[i], s+st);
for(int j=0; j<len[i]; j++)
rev[j] = s[st+len[i]-j-1];
getnxt(rev, len[i]);
exKMP(s+st, rev, len[i], len[i]);
insert(s+st, len[i]);
st += len[i];
}
ans = st = 0;
for(int i=0; i<n; i++){
for(int j=0; j<len[i]; j++)
rev[j] = s[st+len[i]-j-1];
getnxt(s+st, len[i]);
exKMP(rev, s+st, len[i], len[i]);
search(rev, len[i]);
st += len[i];
}
printf("%lld\n", ans);
return 0;
}
_/_/_/_/_/ EOF _/_/_/_/_/