JSOI2013 快乐的JYY(manacher,回文串)
萌新不会PAM
于是用manacher+hash
O(nlogn)过了这题
首先我们有一个结论
对于一个长度n的串,它的本质不同的回文子串数量是O(n)的
然后我们先用manacher算出半径r[i]
然后开一个数组记录一下最长回文子串在原字符串中哪个位置
我们考虑任意一个>=3的回文子串不论是奇是偶,去掉头尾它依然是回文串
又因为只有O(n)个本质不同的回文子串(以下简称子串),所以我们可以考虑用字符串哈希map给每个本质不同的子串标号,然后每个子串的节点把去掉头尾的子串的节点当作父亲,就类似于AC自动机的fail树,意即你访问子节点的串同时一定遍历了父节点的串,然后只有长度为1或2的子串向根连边(把根当作父亲).
于是这就形成了一颗树
于是我们每遍历一个以某个位置为对称轴(可以是字母也可以是两个字母间的空隙)的最长回文子串就给它打个标记,一个回文子串遍历了多少次显然是它树上的结点的子树和,于是我们可以算出每个回文子串在A中出现了几次,同理对B建树,然后把相同的子串在两树中的方案乘起来再累加到ans里,就做完了
/*快乐的JYY*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
#define ll long long
const int maxn = 2e5 + 10;
#define ul unsigned long long
ul mi[maxn];
ll ans = 0;
int head[maxn];
int idcnt = 0;
struct Edge{
int nxt,point;
}edge[maxn*2];
int tot;
void add(int x,int y){
edge[++tot].nxt = head[x];
edge[tot].point = y;
head[x] = tot;
}
struct Str{
char str[maxn]; char s[maxn*2];
int r[maxn] ;int bit[maxn];ul hash[maxn];map<ul,int>id;
ul v[maxn];
ll dp[maxn * 2];
map<ul,ll>f;
int len;
int cnt;
int rt;
#define p 133331
void init(){
for(int i = 1; i <= len; ++i)
hash[i] = hash[i-1] * p + str[i] - 'A' + 1;
}
ul calc(int l,int r){
int k = r - l + 1;
return hash[r] - mi[k] * hash[l-1];
}
void manacher(){
s[++cnt] = '~',s[++cnt] = '#';
for(int i = 1; i <= len; ++i){
s[++cnt] = str[i]; s[++cnt] = '#';
bit[cnt] = i;
}
s[++cnt] = '!';
s[cnt+1] = '\0';
int mr = 0,mid = 0;
for(int i = 2; i <= cnt - 1; ++i){
if(i <= mr) r[i] = min(r[(mid<<1)-i],mr - i + 1);
else r[i] = 1;
while(s[i+r[i]] == s[i-r[i]]) r[i]++;
if(i + r[i] > mr){
mr = i + r[i] - 1;
mid = i;
}
}
}
void build(){
rt = ++idcnt;
for(int i = 2; i <= cnt - 1; ++i){
int L = i - r[i] + 1,R = i + r[i] - 1;
if(L == R && s[L] == '#') continue;
L = bit[L] + 1,R = bit[R];
int lst = 0;
while(L <= R){
ul val = calc(L,R);
if(id.find(val) == id.end()){
id[val] = ++idcnt;
v[idcnt] = val;
if(lst) add(id[val],lst);
}
else{
if(lst) add(id[val],lst);
break;
}
lst = id[val];
if(L == R){
add(rt,id[val]);
}
if(R == L + 1){
add(rt,id[val]);
}
L++,R--;
}
L = i - r[i] + 1,R = i + r[i] - 1;
L = bit[L] + 1,R = bit[R];
ul val = calc(L,R);
dp[id[val]]++;
}
}
void dfs(int x){
for(int i = head[x]; i ; i = edge[i].nxt){
int y = edge[i].point;
dfs(y);
dp[x] += dp[y];
}
f[v[x]] += dp[x];
}
}A,B;
void init(){
mi[0] = 1;
for(int i = 1; i <= 1e5; ++i)
mi[i] = mi[i-1] * p;
scanf("%s",A.str+1);
A.len = strlen(A.str + 1);
A.init();
A.manacher();
A.build();
A.dfs(A.rt);
scanf("%s",B.str+1);
B.len = strlen(B.str + 1);
B.init();
B.manacher();
B.build();
B.dfs(B.rt);
}
void solve(int x){
if(x != A.rt){
ans += A.f[A.v[x]] * B.f[A.v[x]];
}
for(int i = head[x]; i ; i = edge[i].nxt){
int y = edge[i].point;
solve(y);
}
}
int main()
{
init();
solve(A.rt);
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号