链接:https://ac.nowcoder.com/acm/contest/884/I
题意:求string串有多少个本质不同的子串,且这些子串之间两两不存在 a==rev(a),即不存在长度1以上的回文串
题解:
要算string 和 rev(string)的所有子串,对string
和rev(string)建立广义后缀自动机,则理论上所有子串增加了一倍,但实际回文串和 不是回文但a == rev(a)的串没有增加,
比如 aba子串ab和ba。则我们计算出此时不同串个数 ans1, 再计算出string串中回文串数 ans2,则(ans1+ans2)/2即为所求.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2*1e6+5;
const int maxc = 28;
char str[maxn];
struct SMA{
int len[maxn * 2];
int link[maxn * 2];
int cnt[maxn * 2];
int nxt[maxn * 2][maxc];
int idx;
int last;
LL epos[maxn * 2];
LL a[maxn];
void init(){
last = idx = 1;
link[1] = len[1] = 0;
}
//SMA建图
void SMA_Extend(int c){
int x = ++idx;
len[x] = len[last] + 1;
epos[x] = 1;
int p;
for(p = last; p && !nxt[p][c]; p = link[p]) nxt[p][c] = x;
if(!p) link[x] = 1, cnt[1]++;
else{
int q = nxt[p][c]; //p通过c转移到的节点
if(len[p] + 1 == len[q]) //pq是连续的
link[x] = q, cnt[q]++; //将新节点后缀连接指向q即可,q节点的被后缀连接数+1
else{
int nq = ++idx; //不连接,需要复制一份q节点
len[nq] = len[p] + 1; //令nq与p连接
link[nq] = link[q]; //因后面link[q]改变此处不加cnt
memcpy(nxt[nq], nxt[q], sizeof(nxt[q])); //复制q的信息给nq
for(; p && nxt[p][c] == q; p = link[p])
nxt[p][c] = nq; //沿着后缀连接,将所有通过c转移为q
link[q] = link[x] = nq; //将x和q后缀连接改为nq
cnt[nq] += 2; //nq增加两个后缀连接
}
}
last = x;
}
//求不相同子串数量
LL getSubNum(){
LL ans = 0;
for(int i = 2; i <= idx; i++) ans += len[i] - len[link[i]];
return ans;
}
}sma;
struct PAM{
int nxt[maxn][maxc];
int fail[maxn];
int cnt[maxn];
int len[maxn];
int S[maxn];
int last, n, p;
int Create(int rt){
for(int i = 0; i <= 26; i++) nxt[p][i] = 0;
cnt[p] = 0;
len[p] = rt;
return p++;
}
void init(){
p = last = n = 0;
Create(0);
Create(-1);
S[n] = -1;
fail[0] = 1;
}
int getFail(int x){
while(S[n-len[x]-1] != S[n]) x = fail[x];
return x;
}
void Insert(int c){
S[++n] = c;
int cur = getFail(last);
if(!nxt[cur][c]){
int now = Create(len[cur] + 2);
fail[now] = nxt[getFail(fail[cur])][c];
nxt[cur][c] = now;
//num[now] = num[fail[now]] + 1;
}
last = nxt[cur][c];
cnt[last]++;
}
}pam;
int main()
{
scanf("%s", str);
int len = strlen(str);
sma.init();
for(int i = 0; i < len; i++) sma.SMA_Extend(str[i] - 'a');
sma.last = 1;
for(int i = len-1; i >= 0; i--) sma.SMA_Extend(str[i] - 'a');
LL ans1 = sma.getSubNum();
pam.init();
for(int i = 0; i < len; i++){
//printf("fdsjfkds\n");
pam.Insert(str[i] - 'a');
}
//printf(" %d %d\n", pam.p-2, ans1);
printf("%lld\n", (ans1 + pam.p - 2) / 2);
return 0;
}