[JSOI2013]快乐的 JYY
题目链接:https://www.luogu.com.cn/problem/P5685
题解:
回文自动机。对两个字符串分别构造回文自动机。统计每个回文子串出现的次数。
DFS。对两个自动机DFS,对于两个自动机共有的回文子串,ans+=两个自动机该串出现次数的乘积。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 50010;
const int mod = 1000000007;
struct Pam{
char s[maxn];
int cnt, slen, last;
int len[maxn], tim[maxn], num[maxn], fail[maxn], nex[maxn][26];
void init()
{
cnt = -1;
slen = last = 0;
s[0] = '*';
creat(0);
creat(-1);
fail[0] = 1;
}
int creat(int x)
{
cnt++;
len[cnt] = x;
memset(nex[cnt], 0, sizeof(nex[cnt]));
num[cnt] = tim[cnt] = 0;
return cnt;
}
int getfail(int x)
{
while(s[slen-len[x]-1] != s[slen])x = fail[x];
return x;
}
void Insert(char ch)
{
s[++slen] = ch;
int x = ch-'A', cur = getfail(last);
if(!nex[cur][x]){
int now = creat(len[cur]+2);
fail[now] = nex[getfail(fail[cur])][x];
nex[cur][x] = now;
}
last = nex[cur][x];
tim[last]++;
}
void getsum()
{
for(int i=cnt;i>1;i--)
tim[fail[i]] += tim[i];
}
}st1, st2;
int mx, num;
LL ans;
char str1[maxn], str2[maxn];
void dfs(int id1, int id2);
int main()
{
int n, m, i, j, k;
scanf("%s %s", str1, str2);
st1.init();
for(i=0;str1[i];i++)
st1.Insert(str1[i]);
st1.getsum();
st2.init();
for(i=0;str2[i];i++)
st2.Insert(str2[i]);
st2.getsum();
dfs(0, 0);
dfs(1, 1);
printf("%lld\n", ans);
return 0;
}
void dfs(int id1, int id2)
{
if(id1!=0 && id1 != 1)ans += 1LL*st1.tim[id1]*st2.tim[id2];
for(int i=0;i<26;i++)
if(st1.nex[id1][i] && st2.nex[id2][i])
dfs(st1.nex[id1][i], st2.nex[id2][i]);
}