链接:https://ac.nowcoder.com/acm/contest/886/C
来源:牛客网
题目描述
Doctor has a string s consisting of only lowercase letters. Doctor has got the set of all palindromic substrings of a string s, denoted by the set S. Now, he wants to choose two distinct strings a and b from the set S which satisfy that the string a is a substring of the string b. How many different pairs (a, b) can Doctor choose?
输入描述:
There are multiple test cases. The first line contains an integer T (1≤T≤51), indicating the number of test cases. Test cases are given in the following.
Each test case consists of only one line, containing a non-empty string s (1≤∣s∣≤1000001 ), consisting of only lowercase letters.
输出描述:
For each test case, output "Case #x: y" in one line (without quotes), where x indicates the case number starting from 1, and y denotes the answer to this test case.
示例1
输入
4
aaaa
abba
abacaba
abc
输出
Case #1: 6
Case #2: 4
Case #3: 14
Case #4: 0
题解:
看了一下午回文树,晚上又看了一个多小时,终于看懂了回文树的原理。
参考博客:
1. https://blog.csdn.net/lwfcgz/article/details/48739051
2. https://www.cnblogs.com/nbwzyzngyl/p/8260921.html
3. https://blog.csdn.net/u013534123/article/details/98472486
首先看了下第一个博客,对回文树的里的一些概念理解了,基本原理理解了。然后看了下第三个博客,第三个博客是这个题的题解,然后有一些地方我就理解不了,然后又百度了一下回文树,找到了第二篇博客,第二篇的博客里的图画的很棒,然后差不多又看了很长时间终于看懂了这道题,我太菜了。
我看第三篇博客,博主说 t[i]的取值有三种情况,分别是 0,1,2,但是我觉得值不可能是0。因为树dfs的时候,通过next指针向下遍历,每个节点走一次, 如果是通过v[fail[x]]标记了,那条链遍历完又恢复了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int ALP=26;
char s[maxn];
struct Palindromic_Tree {
int son[maxn][ALP];
int fail[maxn];
int cnt[maxn];
int num[maxn];
int len[maxn];
int S[maxn];
int v[maxn];
int sz[maxn];
int t[maxn];
int last;
int n;
int p;
int newnode(int l) {
memset(son[p], 0, sizeof(son[p]));
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) {
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 (!son[cur][c]) {
int now = newnode(len[cur] + 2);
fail[now] = son[get_fail(fail[cur])][c];
son[cur][c] = now;
num[now] = num[fail[now]] + 1;
}
last = son[cur][c];
cnt[last]++;
}
void count() {
for (int i = p - 1; i >= 0; i--) cnt[fail[i]] += cnt[i];
}
void dfs(int x){
if(v[fail[x]]!=0) t[x]=1;
else t[x]=2;
v[x]++,v[fail[x]]++;
sz[x]=1;
for(int i=0;i<26;i++){
if(son[x][i]){
dfs(son[x][i]);
sz[x]+=sz[son[x][i]];
}
}
v[x]--,v[fail[x]]--;
}
ll solve(){
dfs(0),dfs(1);
ll ans=0;
for(int i=2;i<p;i++){
ans+=sz[i]*t[i]-1;
}
return ans;
}
}a;
int main(){
int t;
cin>>t;
for(int cas=1;cas<=t;cas++){
scanf("%s",s);
a.init();
int n=strlen(s);
for(int i=0;i<n;i++) a.add(s[i]);
printf("Case #%d: %lld\n",cas,a.solve());
}
return 0;
}