题目链接:https://vjudge.net/problem/UVALive-7041
WA:相乘爆long long
RE:新加入特殊间隔符的特殊间隔符号越界了
解题思路:
让两个字符串共用同一棵回文树,加完第一个串之后在两者之间加一个不会出现的字符,防止产生两个字符串之间的回文串。
然后就跟原本只有一个串时cnt的统计差不多,现在分成两部分,第一个字符串的字符计入cntl,第二个计入cntr,由于中间有个特殊间隔符号可以保证两边计数的点代表的回文串是这个串自身的。
然后跑一遍count,求得真正的cntl,cntr
由于共用同一棵回文树,下标相同的两个cntl,cntr代表的回文串相同。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define rof1(i,a,b) for (int i=a;i>=b;i--)
#define rof0(i,a,b) for (int i=a;i>b;i--)
#define pb push_back
#define fi first
#define se second
#define debug(x) printf("----Line %s----\n",#x)
#define pt(x,y) printf("%s = %d\n",#x,y)
#define INF 0x3f3f3f3f
#define df(x) ll x;scanf("%I64d",&x)
#define df2(x,y) ll x,y;scanf("%I64d %I64d",&x,&y)
#define mod 1000000007
#define duozu(T) int T;scanf("%d",&T);while (T--)
const int N = 4e5+10;
const int maxn = 4e5+10;
const int ALP = 27;
int dd;
char ss[N];
struct PAM{ // 每个节点代表一个回文串
int next[maxn][ALP]; // next指针,参照Trie树
int fail[maxn]; // fail失配后缀链接
int cntl[maxn],cntr[maxn]; // 此回文串出现个数
int len[maxn]; // 回文串长度
int s[maxn]; // 存放添加的字符
int last; //指向上一个字符所在的节点,方便下一次add
int n; // 已添加字符个数
int p; // 节点个数
int newnode(int w){//新建一个节点,长度初始化为这个节点代表的回文串长度
for(int i=0;i<ALP;i++)
next[p][i] = 0;
cntl[p] = 0;
cntr[p] = 0;
len[p] = w;
return p++;
}
void init(){
p = 0;
newnode(0);
newnode(-1);
last = 0;
n = 0;
s[n] = -1; // 开头放一个字符集中没有的字符,减少特判
fail[0] = 1;
}
int get_fail(int x){
while(s[n-len[x]-1] != s[n]) x = fail[x];
return x;
}
void add(int c){
c -= 'a';
s[++n] = c;
int cur = get_fail(last);
if(!next[cur][c]){
int now = newnode(len[cur]+2);//len赋值在这
fail[now] = next[get_fail(fail[cur])][c];
next[cur][c] = now;
}
last = next[cur][c];
if (n>dd)cntr[last]++;
else if (n<dd)cntl[last]++;
}
void count(){
for(int i=p-1;i>=0;i--){
cntr[fail[i]] += cntr[i];
cntl[fail[i]] += cntl[i];
}
}
}pam;
int main()
{
//freopen("C:/Users/DELL/Desktop/input.txt", "r", stdin);
//freopen("C:/Users/DELL/Desktop/my.txt", "w", stdout);
int ica = 1;
duozu(T){
scanf("%s",ss);
int len = strlen(ss);
ss[len] = 'z'+1;
dd = len+1;
scanf("%s",ss+len+1);
int llen = len+1+strlen(ss+len+1);
pam.init();
for0(i,0,llen) pam.add(ss[i]);
pam.count();
ll ans = 0;
for0(i,2,pam.p){
ans += (ll)pam.cntl[i]*pam.cntr[i];
}
printf("Case #%d: %lld\n",ica++,ans);
}
return 0;
}