bzoj4480: [Jsoi2013]快乐的jyy
Description
【故事背景】
JYY在JSOI有很多很多的好朋友,比如PUPPY,KFC还有PUPPUP。因为
有了这么多的好朋友,所以JYY每天都很快乐。某天,JYY发现好朋友之间关
系的好坏和名字有很大的关系,比如PUPPY和PUPPUP的关系就特别好,但是
和KFC的关系就很一般。JYY苦思冥想终于发现了其中的规律,现在JYY想知
道两个朋友之间关系的好坏,你能帮助JYY么?
【问题描述】
给定两个字符串A和B,表示JYY的两个朋友的名字。我们用A(i,j)表示A
字符串中从第i个字母到第j个字母所组成的子串。同样的,我们也可以定义B(x,y)。
JYY发现两个朋友关系的紧密程度,等于同时满足如下条件的四元组(i,j,x,y)
的个数:
1:1<=i<=j<=|A|
2:1<=x<=y<=|B|
3:A(i,j)=B(x,y)
4:A(i,j)是回文串
这里表示字符串A的长度。
JYY希望你帮助他计算出这两个朋友之间关系的紧密程度。
Input
数据包行两行由大写字母组成的字符串A和B
1≤|A|,|B|≤50000。
Output
包含一行一个整数,表示紧密程度,也就是满足要求的4元组个数
Sample Input
PUPPY
PUPPUP
Sample Output
17
分析
基本上是裸的。
建两个自动机,相同节点的cnt乘法原理一下即可。
代码
#include<cstdio>
#include<cstring>
const int N = 5e4 + 10;
long long ans;
struct PAM {
int ch[N][26], len[N], S[N], f[N], cnt[N], sz, ls, L;
PAM() {len[1] = -1; f[0] = 1; S[0] = -1; sz = 1;}
int F(int p) {for(;S[L - len[p] - 1] != S[L]; p = f[p]) ; return p;}
void Extend(int c) {
S[++L] = c; int p = F(ls), np;
if(!ch[p][c]) {
len[np = ++sz] = len[p] + 2;
f[np] = ch[F(f[p])][c]; ch[p][c] = np;
}
++cnt[ls = ch[p][c]];
}
void Cnt() {for(int i = sz; i; --i) cnt[f[i]] += cnt[i];}
void Work() {
char ch = getchar();
for(;ch < 'A' || ch > 'Z'; ch = getchar()) ;
for(;ch >= 'A' && ch <= 'Z'; ch = getchar()) Extend(ch - 'A');
Cnt();
}
}p[2];
void Dfs(int u, int v) {
if(p[0].len[u] > 0) ans += 1LL * p[0].cnt[u] * p[1].cnt[v];
for(int c = 0;c < 26; ++c)
if(p[0].ch[u][c] && p[1].ch[v][c])
Dfs(p[0].ch[u][c], p[1].ch[v][c]);
}
int main() {
p[0].Work(); p[1].Work();
Dfs(0, 0); Dfs(1, 1); printf("%lld\n", ans);
return 0;
}