Problem:
C: Common Palindromes

ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．

今日の修行は，文字列中にある回文を探すことによって，文章から隠れたメッセージを読解する能力を高めようというものである．回文はたくさんあるかもしれないので，探すついでに個数も数えてしまいたい．

2 つの文字列 S, T が与えられるので，以下を満たす整数の組 (i, j, k, l) の個数を求めたい．

1 ≤ i ≤ j ≤ (S の長さ)．

1 ≤ k ≤ l ≤ (T の長さ)．

S の i 文字目から j 文字目までを取り出した部分文字列は，T の k 文字目から l 文字目までを取り出した部分文字列と同一であり，さらにこれらは回文 (左から読んでも右から読んでも同じになる文字列) となっている．

Input

S
T

文字列 S, T はともに長さが 1 以上 50,000 以下であり，アルファベット大文字からなる．

Output

条件を満たす整数の組 (i, j, k, l) の個数を 1 行に出力せよ．

Sample Input 1

ICPC
CPCPC

Sample Output 1

10

Sample Input 2

BABBAB
ABBA

Sample Output 2

14

Sample Input 3

MYON
USAGI

Sample Output 3

0

Solution in C++ (judge verdict: Wrong Answer)

#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define INF 0x3f3f3f3f
#define MAX_N 50000 * 4 + 100
#define MAX_DAT_SIZE (1<<19) - 1
using namespace std;

int K, n;
int rank[MAX_N];
int   sa[MAX_N];
int  tmp[MAX_N];
int  lcp[MAX_N];
int  stc[MAX_N];
int  stv[MAX_N];
int dat[MAX_DAT_SIZE], dat_size;
int LP[2][MAX_N]; //even & odd

string A, B, S;

void init_rmq(int k, int l, int r){
	if(r - l == 1){
		if(l <= n) dat[k] = lcp[l];
		return;
	}
	int lch = 2 * k + 1, rch = 2 * k + 2;
	init_rmq(lch, l, (l + r) / 2);
	init_rmq(rch, (l + r) / 2, r);
	dat[k] = min(dat[lch], dat[rch]);
}
void init_rmq(){
	memset(dat, 0x3f, sizeof(dat));
	dat_size = 1;
	while(dat_size <= n) dat_size *= 2;

	init_rmq(0, 0, dat_size);
}
int query(int a, int b, int k, int l, int r){
	if(b <= l || a >= r) return INF;
	if(a <= l && b >= r) return dat[k];

	int r1 = query(a, b, 2 * k + 1, l, (l + r) / 2);
	int r2 = query(a, b, 2 * k + 2, (l + r) / 2, r);

	return min(r1, r2);
}
int query(int a, int b){
	return query(a, b, 0, 0, dat_size);
}
bool compare_sa(int i, int j){
	if(rank[i] != rank[j]) return rank[i] < rank[j];
	else{
		int ri = i + K <= n ? rank[i + K] : -1;
		int rj = j + K <= n ? rank[j + K] : -1;
		return ri < rj;
	}
}
void construct_sa(){
	for(int i = 0; i <= n; i++){
		sa[i] = i;
		rank[i] = i < n ? S[i] : -1;
	}
	for(K = 1; K <= n; K *= 2){
		sort(sa, sa + n + 1, compare_sa);

		tmp[sa[0]] = 0;
		for(int i = 1; i <= n; i++){
			tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
		}
		for(int i = 0; i <= n; i++){
			rank[i] = tmp[i];
		}
	}
}
void construct_lcp(){
	memset(lcp, 0, sizeof(lcp));
	for(int i = 0; i <= n; i++) rank[sa[i]] = i;

	int h = 0;
	lcp[0] = 0;
	
	for(int i = 0; i < n; i++){
		int j = sa[rank[i] - 1];

		if(h > 0) h--;

		for(; j + h <= n && i + h <= n; h++){
			if(S[i + h] != S[j + h]) break;
		}
		lcp[rank[i] - 1] = h;
	}
}
void calc_LP(int k, string T){
	string temp = T;
	reverse(temp.begin(), temp.end());
	S = T + '$' + temp;
	n = S.length();
	construct_sa();
	construct_lcp();
	init_rmq();
	/***
	for(int i = 0; i <= n; i++){
		printf("%2d : %2d %2d ", i, sa[i], lcp[i]);
		cout<<S.substr(sa[i])<<endl;
	}	
	/***/

	for(int i = 0; i < T.length(); i++){
		int j = (A.length() + 1) * k + i;
		LP[0][j] = query(min(rank[i], rank[2 * T.length() - i]), 
		                 max(rank[i], rank[2 * T.length() - i]));	
	}
	LP[1][(2 * A.length() + 1) * k] = 0;
	for(int i = 1; i < T.length(); i++){
		int j = (A.length() + 1) * k + i;
		LP[1][j] = query(min(rank[i], rank[2 * T.length() - i + 1]),
		                 max(rank[i], rank[2 * T.length() - i + 1]));
	}
	//cout<<endl;
}
int calc_CLP(int is_A, int k){
	int m = A.length(), res = 0, contribution = 0, t = 0;

	for(int i = 0; i <= n; i++){
		int v = min(min(lcp[i], LP[k][sa[i]]), LP[k][sa[i + 1]]), c = !((sa[i] < m) ^ is_A);


		if(c == 0){
			res += contribution;
//			printf("%d : contribution = %d\n", i, contribution);
		}
		
		while(t > 0 && stv[t - 1] >= v){
			contribution -= stv[t - 1] * stc[t - 1];
			c += stc[t - 1];
			t--;
		}
		stv[t] = v;
		stc[t++] = c;
		contribution += v * c;
	}
//	printf("res = %d\n\n", res);
	return res;
}
int solve(){
	calc_LP(0, A);
	calc_LP(1, B);	
	/***
	for(int i = 0; i < A.length(); i++){
		printf("%c ", A[i]);
	}
	printf("  ");
	for(int i = 0; i < B.length(); i++){
		printf("%c ", B[i]);
	}
	printf("\n");
	for(int k = 0; k < 2; k++){
		for(int i = 0; i < A.length() + B.length() + 1; i++){
			printf("%d ", LP[k][i]);
		}
		cout<<endl;
	}
	/***/

		
	S = A + '$' + B;
	n = S.length();
	construct_sa();
	construct_lcp();
	/***
	for(int i = 0; i <= n; i++){
		printf("%2d : %2d %2d %2d ", i, sa[i] < A.length(), lcp[i], LP[0][sa[i]]);
		cout<<S.substr(sa[i])<<endl;
	}
	/***/
	return calc_CLP(1, 0) + calc_CLP(0, 0) + calc_CLP(1, 1) + calc_CLP(0, 1);
}
int main(){
	cin>>A>>B;
	printf("%d\n", solve());
	return 0;
}