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元组个数
题解:
感觉回文自动机的题比AC自动机和SAM友好多了(
其实只需要知道A,B串中有多少对相同的回文串就好了,由于回文自动机上的结点代表的回文串都是唯一的,所以我们可以分别建回文自动机,然后求出每个回文串的出现次数,同时dfs奇根和偶根,出现次数相乘然后累加即可
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
#define pii pair<int,int>
#define mp(a,b) make_pair(a,b)
const int MAXN = 5e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
char s[MAXN],t[MAXN];
struct PAM{
int nxt[MAXN][26],fail[MAXN],cnt[MAXN],len[MAXN];
int tot,last;
inline void Init(){
len[0]=0,len[1]=-1;
fail[0]=fail[1]=1;
last=0,tot=1;
}
inline void Insert(int x,int en,char *s){
int rt=last;
while(s[en]!=s[en-len[rt]-1]) rt=fail[rt];
if(!nxt[rt][x]){
int tmp=fail[rt]; ++tot;
while(s[en]!=s[en-len[tmp]-1]) tmp=fail[tmp];
fail[tot]=nxt[tmp][x];
nxt[rt][x]=tot;
len[tot]=len[rt]+2;
}
last = nxt[rt][x]; cnt[last]++;
}
inline void solve(){
for(int i=tot;i;i--) cnt[fail[i]] += cnt[i];
}
}p1,p2;
LL ans;
void dfs(int u,int v){
if(u>1 && v>1) ans+=1LL*p1.cnt[u]*p2.cnt[v];
for(int i=0;i<26;i++)
if(p1.nxt[u][i] && p2.nxt[v][i])
dfs(p1.nxt[u][i],p2.nxt[v][i]);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
p1.Init(); p2.Init();
cin>>(s+1)>>(t+1);
int n=strlen(s+1),m=strlen(t+1);
for(int i=1;i<=n;i++) p1.Insert(s[i]-'A',i,s);
for(int i=1;i<=m;i++) p2.Insert(t[i]-'A',i,t);
p1.solve(); p2.solve();
dfs(1,1); dfs(0,0); cout<<ans<<'\n';
return 0;
}