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

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

const long long MOD = 10000000000000099;
const long long BASE = 1333;
const int MAXN = 5 * 100000;

long long POWER[MAXN + 1];

long long mul(long long a, long long b) {
    return ((__int128_t)a * b) % MOD;
}

class RollingHash {
public:
    RollingHash(const string& s) : size(s.size()), str(s) {
        hashed.resize(size + 1);
        for (int i = 0; i < size; ++i) {
            hashed[i + 1] = mul(hashed[i], BASE) + (s[i]);
            hashed[i + 1] %= MOD;
        }
    }

    long long query(int l, int r) {
        assert(0 <= l && l <= r && r <= size);
        return (hashed[r] - mul(hashed[l], POWER[r - l]) + MOD) % MOD;
    }

private:
    string str;
    vector<long long> hashed;
    int size;
};

class Eertree {
public:
    Eertree(const string& s) : str(s), size(s.size()), r1(s), r2(string(s.rbegin(), s.rend())) {}

    void build() {
        const int BEGIN = 'A'; // or 'a'
        const int PALINDROME_SIZE = 2 * size;
        vector<vector<int>> G(PALINDROME_SIZE);
        H.resize(PALINDROME_SIZE);
        W.resize(PALINDROME_SIZE, 0);
        vector<unordered_map<long long, int>> ptr(27);
        
        ptr[26][0] = 0;
        H[0] = {26, 0};
        int free = 1;

        for (int i = 0; i < size; ++i) {
            int ID = str[i] - BEGIN;
            int ok = -1, ng = min(i, size - i - 1) + 1;

            while (ng - ok > 1) {
                int x = (ng + ok) >> 1;
                long long h1 = r1.query(i + 1, i + 1 + x);
                long long h2 = r2.query(size - i, size - i + x);
                if (ptr[ID].count(h1) && ptr[ID][h1] >= 0 && h1 == h2) ok = x;
                else ng = x;
            }

            if (ok == -1) {
                ptr[ID][0] = free;
                H[free] = {ID, 0};
                free++;
                ok = 0;
            }

            int par = ptr[ID][r1.query(i + 1, i + 1 + ok)];
            for (int j = ok + 1; j < min(i + 1, size - i); ++j) {
                if (str[i + j] == str[i - j]) {
                    long long h1 = r1.query(i + 1, i + j + 1);
                    ptr[ID][h1] = free;
                    G[par].push_back(free);
                    H[free] = {ID, h1};
                    par = free;
                    free++;
                } else {
                    break;
                }
            }
            W[par] += 1;

            // Centroid = ''
            ok = 0;
            ng = min(i, size - i - 1) + 1;
            ID = 26;

            while (ng - ok > 1) {
                int x = (ng + ok) >> 1;
                long long h1 = r1.query(i, i + x);
                long long h2 = r2.query(size - i, size - i + x);
                if (ptr[ID].count(h1) && ptr[ID][h1] >= 0 && h1 == h2) ok = x;
                else ng = x;
            }

            par = ptr[ID][r1.query(i, i + ok)];
            for (int j = ok + 1; j < min(i + 1, size - i + 1); ++j) {
                if (str[i + j - 1] == str[i - j]) {
                    long long h1 = r1.query(i, i + j);
                    ptr[ID][h1] = free;
                    G[par].push_back(free);
                    H[free] = {ID, h1};
                    par = free;
                    free++;
                } else {
                    break;
                }
            }
            W[par] += 1;
        }

        function<long long(int)> dfs = [&](int v) {
            for (int nxt : G[v]) {
                W[v] += dfs(nxt);
            }
            return W[v];
        };

        for (int ID = 0; ID < 27; ++ID) {
            if (ptr[ID].count(0) && ptr[ID][0] >= 0) dfs(ptr[ID][0]);
        }
        W[0] = 0;
    }

    vector<long long> getW() const { return W; }
    vector<pair<int, long long>> getH() const { return H; }

private:
    string str;
    int size;
    RollingHash r1, r2;
    vector<long long> W;
    vector<pair<int, long long>> H;
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    for (int i = 0; i <= MAXN; ++i) {
        POWER[i] = (i == 0) ? 1 : mul(POWER[i - 1], BASE);
    }

    string s, t;
    cin >> s >> t;

    Eertree palS(s);
    Eertree palT(t);
    palS.build();
    palT.build();

    vector<long long> SW = palS.getW();
    vector<long long> TW = palT.getW();
    vector<pair<int, long long>> SH = palS.getH();
    vector<pair<int, long long>> TH = palT.getH();

    unordered_map<long long, array<long long, 2>> pair;
    
    for (size_t i = 0; i < SW.size(); ++i) {
        pair[SH[i].first*MOD+SH[i].second][0] += SW[i];
    }
    for (size_t i = 0; i < TW.size(); ++i) {
        pair[TH[i].first*MOD+TH[i].second][1] += TW[i];
    }

    long long ans = 0;
    for (const auto& p : pair) {
        ans += p.second[0] * p.second[1];
    }

    cout << ans << '\n';
    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 25348
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

const long long MOD = (1LL << 61) - 1;
const long long BASE = 1333;
const int MAXN = 5 * 100000;

long long POWER[MAXN + 1];

long long mul(long long a, long long b) {
    return ((__int128_t)a * b) % MOD;
}

class RollingHash {
public:
    RollingHash(const string& s) : size(s.size()), str(s) {
        hashed.resize(size + 1);
        for (int i = 0; i < size; ++i) {
            hashed[i + 1] = mul(hashed[i], BASE) + (s[i]);
            hashed[i + 1] %= MOD;
        }
    }

    long long query(int l, int r) {
        assert(0 <= l && l <= r && r <= size);
        return (hashed[r] - mul(hashed[l], POWER[r - l]) + MOD) % MOD;
    }

private:
    string str;
    vector<long long> hashed;
    int size;
};

class Eertree {
public:
    Eertree(const string& s) : str(s), size(s.size()), r1(s), r2(string(s.rbegin(), s.rend())) {}

    void build() {
        const int BEGIN = 'A'; // or 'a'
        const int PALINDROME_SIZE = 2 * size;
        vector<vector<int>> G(PALINDROME_SIZE);
        H.resize(PALINDROME_SIZE);
        W.resize(PALINDROME_SIZE, 0);
        vector<unordered_map<long long, int>> ptr(27);
        
        ptr[26][0] = 0;
        H[0] = {26, 0};
        int free = 1;

        for (int i = 0; i < size; ++i) {
            int ID = str[i] - BEGIN;
            int ok = -1, ng = min(i, size - i - 1) + 1;

            while (ng - ok > 1) {
                int x = (ng + ok) >> 1;
                long long h1 = r1.query(i + 1, i + 1 + x);
                long long h2 = r2.query(size - i, size - i + x);
                if (ptr[ID].count(h1) && ptr[ID][h1] >= 0 && h1 == h2) ok = x;
                else ng = x;
            }

            if (ok == -1) {
                ptr[ID][0] = free;
                H[free] = {ID, 0};
                free++;
                ok = 0;
            }

            int par = ptr[ID][r1.query(i + 1, i + 1 + ok)];
            for (int j = ok + 1; j < min(i + 1, size - i); ++j) {
                if (str[i + j] == str[i - j]) {
                    long long h1 = r1.query(i + 1, i + j + 1);
                    ptr[ID][h1] = free;
                    G[par].push_back(free);
                    H[free] = {ID, h1};
                    par = free;
                    free++;
                } else {
                    break;
                }
            }
            W[par] += 1;

            // Centroid = ''
            ok = 0;
            ng = min(i, size - i - 1) + 1;
            ID = 26;

            while (ng - ok > 1) {
                int x = (ng + ok) >> 1;
                long long h1 = r1.query(i, i + x);
                long long h2 = r2.query(size - i, size - i + x);
                if (ptr[ID].count(h1) && ptr[ID][h1] >= 0 && h1 == h2) ok = x;
                else ng = x;
            }

            par = ptr[ID][r1.query(i, i + ok)];
            for (int j = ok + 1; j < min(i + 1, size - i + 1); ++j) {
                if (str[i + j - 1] == str[i - j]) {
                    long long h1 = r1.query(i, i + j);
                    ptr[ID][h1] = free;
                    G[par].push_back(free);
                    H[free] = {ID, h1};
                    par = free;
                    free++;
                } else {
                    break;
                }
            }
            W[par] += 1;
        }

        function<long long(int)> dfs = [&](int v) {
            for (int nxt : G[v]) {
                W[v] += dfs(nxt);
            }
            return W[v];
        };

        for (int ID = 0; ID < 27; ++ID) {
            if (ptr[ID].count(0) && ptr[ID][0] >= 0) dfs(ptr[ID][0]);
        }
        W[0] = 0;
    }

    vector<long long> getW() const { return W; }
    vector<pair<int, long long>> getH() const { return H; }

private:
    string str;
    int size;
    RollingHash r1, r2;
    vector<long long> W;
    vector<pair<int, long long>> H;
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    for (int i = 0; i <= MAXN; ++i) {
        POWER[i] = (i == 0) ? 1 : mul(POWER[i - 1], BASE);
    }

    string s, t;
    cin >> s >> t;

    Eertree palS(s);
    Eertree palT(t);
    palS.build();
    palT.build();

    vector<long long> SW = palS.getW();
    vector<long long> TW = palT.getW();
    vector<pair<int, long long>> SH = palS.getH();
    vector<pair<int, long long>> TH = palT.getH();

    unordered_map<long long, array<long long, 2>> pair;
    
    for (size_t i = 0; i < SW.size(); ++i) {
        pair[SH[i].first*MOD+SH[i].second][0] += SW[i];
    }
    for (size_t i = 0; i < TW.size(); ++i) {
        pair[TH[i].first*MOD+TH[i].second][1] += TW[i];
    }

    long long ans = 0;
    for (const auto& p : pair) {
        ans += p.second[0] * p.second[1];
    }

    cout << ans << '\n';
    return 0;
}
accuracy: 0.11666666666666667
time_ms: 300
memory_kb: 22600
final_rank: 18

code_snippet: #include <algorithm>
#include <limits>
#include <map>
#include <numeric>
#include <ranges>
#include <type_traits>
#include <vector>
namespace nono {
template <class T = char>
class Eertree {
    struct Node {
        Node(int len, int parent = 0, int link = 0): len(len), parent(parent), link(link) {}
        int len;
        int parent;
        int link;
        std::map<T, int> to;
    };
   public:
    Eertree(): pos_(0) {
        nodes_.emplace_back(Node(-1));
        nodes_.emplace_back(Node(0));
        seq_.push_back(std::numeric_limits<T>::max());
    }
    int size() { return nodes_.size() - 2; }
    void add(T c) {
        const int i = seq_.size();
        seq_.push_back(c);
        pos_ = go(pos_, i);
        if (!nodes_[pos_].to.contains(c)) {
            nodes_[pos_].to[c] = nodes_.size();
            int link = pos_ == 0 ? 1 : nodes_[go(nodes_[pos_].link, i)].to[c];
            nodes_.emplace_back(nodes_[pos_].len + 2, pos_, link);
        }
        pos_ = nodes_[pos_].to[c];
        node_id_.push_back(pos_);
    }
    template <std::ranges::random_access_range R>
    void add(const R& seq) {
        static_assert(std::is_same_v<typename R::value_type, T>);
        for (auto c: seq) add(c);
    }
    std::vector<int> node_id() { return node_id_; }
    std::vector<Node> nodes() { return nodes_; }
    std::vector<int> freq() {
        std::vector<int> ids(nodes_.size());
        std::iota(ids.begin(), ids.end(), 0);
        std::sort(ids.begin(), ids.end(),
            [&](int lhs, int rhs) { return nodes_[lhs].len > nodes_[rhs].len; });
        std::vector<int> result(nodes_.size());
        for (auto id: node_id_) result[id]++;
        for (auto id: ids) { result[nodes_[id].link] += result[id]; }
        return result;
    }
   private:
    bool fail(int pos, int i) { return seq_[i] != seq_[i - nodes_[pos].len - 1]; }
    int go(int pos, int i) {
        while (fail(pos, i)) pos = nodes_[pos].link;
        return pos;
    }
    int pos_;
    std::vector<T> seq_;
    std::vector<int> node_id_;
    std::vector<Node> nodes_;
};
} // namespace nono
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
template <class T>
using max_heap = priority_queue<T>;
template <class T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
#define rep(i, l, r) for (ll i = (l); i < (r); i++)
#define rrep(i, r, l) for (ll i = (r); i-- > (l);)
#define all(x) begin(x), end(x)
template <class T>
bool chmin(T& lhs, T rhs) {
    return lhs > rhs ? (lhs = rhs, true) : false;
}
template <class T>
bool chmax(T& lhs, T rhs) {
    return lhs < rhs ? (lhs = rhs, true) : false;
}
struct IOIO {
    IOIO() { cin.tie(0)->sync_with_stdio(0); }
} ioio;
template <class S, class T>
ostream& operator<<(ostream& os, const pair<S, T>& p) {
    os << '(' << p.first << ", " << p.second << ')';
    return os;
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& vs) {
    os << '{';
    rep(i, 0, (int)vs.size()) os << vs[i] << (i + 1 == (int)vs.size() ? "" : ", ");
    os << '}';
    return os;
}
template <class T>
ostream& operator<<(ostream& os, const set<T>& vs) {
    os << '{';
    for (auto it = vs.begin(); it != vs.end(); it++) {
        if (it != vs.begin()) { os << ", "; }
        os << *it;
    }
    os << '}';
    return os;
}
template <class T, class U>
ostream& operator<<(ostream& os, const map<T, U>& vs) {
    os << '{';
    for (auto it = vs.begin(); it != vs.end(); it++) {
        if (it != vs.begin()) { os << ", "; }
        os << *it;
    }
    os << '}';
    return os;
}
#ifdef DEBUG
void dump_func() { cerr << endl; }
template <class Head, class... Tail>
void dump_func(Head&& head, Tail&&... tail) {
    cerr << head;
    if (sizeof...(Tail) > 0) { cerr << ", "; }
    dump_func(std::move(tail)...);
}
#define dump(...) cerr << "[" + string(#__VA_ARGS__) + "] ", dump_func(__VA_ARGS__)
#else
#define dump(...) static_cast<int>(0)
#endif
int main() {
    string s, t;
    cin >> s >> t;
    nono::Eertree Stree, Ttree;
    Stree.add(s);
    Ttree.add(t);
    auto Sfreq = Stree.freq();
    auto Tfreq = Ttree.freq();
    auto Snodes = Stree.nodes();
    auto Tnodes = Ttree.nodes();
    ll ans = 0;
    auto dfs = [&](auto&& self, int si, int ti) -> void {
        if (Snodes[si].len > 0) { ans += (ll)Sfreq[si] * Tfreq[ti]; }
        for (auto [c, to]: Snodes[si].to) {
            if (Tnodes[ti].to.contains(c)) { self(self, to, Tnodes[ti].to[c]); }
        }
    };
    dfs(dfs, 0, 0);
    dfs(dfs, 1, 1);
    cout << ans << '\n';
}
accuracy: 1
time_ms: 10
memory_kb: 28336
final_rank: 9

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

template < class char_type > struct eertree {
    using size_type = int;
    struct node_type {
        map<char_type, size_type> nxt;
        size_type link, len, count;

        node_type(size_type link, size_type len, size_type count) : link(link), len(len), count(count) {}
    };

    size_type lsp;
    vector<char_type> s;
    vector<node_type> g;

    eertree() : lsp(0) {
        g.emplace_back(0, -1, 0); // odd
        g.emplace_back(0,  0, 0); // even
    }

    // return node(c + str(?) + c)
    size_type find(size_type v) const {
        const size_type n = s.size() - 1;
        while(true) {
            const size_type i = n - g[v].len - 1;
            if(0 <= i and s[i] == s[n]) return v;
            v = g[v].link;
        }
    }

    void push_back(const char_type c) {
        s.push_back(c);
        const size_type v = find(lsp);

        if(g[v].nxt.count(c)) {
            lsp = g[v].nxt[c];
            g[lsp].count++;
        } else {
            lsp = g[v].nxt[c] = g.size();
            g.emplace_back(v == 0 ? 1 : g[find(g[v].link)].nxt[c], 1 + g[v].len + 1, 1);
        }
    }

    vector<size_type> freq() const {
        vector<size_type> freq(g.size(), 0);
        for(size_type i = size_type(g.size()) - 1; i > 0; i--) {
            freq[i] += g[i].count;
            freq[g[i].link] += freq[i];
        }
        return freq;
    }

    string str(size_type v) const {
        if(v == 0) return "odd(-1)";
        if(v == 1) return "even(0)";
        string res = "";
        function<bool(size_type)> dfs = [&](size_type x) -> bool {
            if(x == v) return true;
            for(auto [c, nx] : g[x].nxt) {
                if(dfs(nx)) {
                    res.push_back(c);
                    return true;
                }
            }
            return false;
        }; dfs(0); dfs(1);
        string rr = res; reverse(rr.begin(), rr.end());
        if(g[v].len % 2 == 1) rr.pop_back();
        return res + rr;
    }
};

int main() {
    string S = in(), T = in();

    auto f = [&](const string& x) {
        eertree<char> tree;
        for(char c : x) tree.push_back(c);
        vector<int> freq = tree.freq();
        const int n = freq.size();
        i64 ans = 0;
        for(int i : rep(2, n))
            ans += i64(freq[i]) * (freq[i] - 1) / 2;
        return ans;
    };

    print(f(S + "!?" + T) - f(S) - f(T));
}
accuracy: 1
time_ms: 10
memory_kb: 16656
final_rank: 2

code_snippet: #ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; using ull = unsigned long long; // -2^63 ～ 2^63 = 9 * 10^18（int は -2^31 ～ 2^31 = 2 * 10^9）
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;	using vvvvi = vector<vvvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;	using vvvvl = vector<vvvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
const vi DX = { 1, 0, -1, 0 }; // 4 近傍（下，右，上，左）
const vi DY = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004003104004004LL; // (int)INFL = 1010931620;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), x))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), x))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define YES(b) {cout << ((b) ? "YES\n" : "NO\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素（変更不可能）
#define repea(v, a) for(auto& v : (a)) // a の全要素（変更可能）
#define repb(set, d) for(int set = 0, set##_ub = 1 << int(d); set < set##_ub; ++set) // d ビット全探索（昇順）
#define repis(i, set) for(int i = lsb(set), bset##i = set; i >= 0; bset##i -= 1 << i, i = lsb(bset##i)) // set の全要素（昇順）
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て（昇順）
#define smod(n, m) ((((n) % (m)) + (m)) % (m)) // 非負mod
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了
#define inQ(x, y, u, l, d, r) ((u) <= (x) && (l) <= (y) && (x) < (d) && (y) < (r)) // 矩形内判定

// 汎用関数の定義
template <class T> inline ll pow(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新（更新されたら true を返す）
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新（更新されたら true を返す）
template <class T> inline T get(T set, int i) { return (set >> i) & T(1); }

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

#endif // 折りたたみ用


#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;

#ifdef _MSC_VER
#include "localACL.hpp"
#endif

//using mint = modint1000000007;
using mint = modint998244353;
//using mint = modint; // mint::set_mod(m);

namespace atcoder {
	inline istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
	inline ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
}
using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>; using vvvvm = vector<vvvm>;
#endif


#ifdef _MSC_VER // 手元環境（Visual Studio）
#include "local.hpp"
#else // 提出用（gcc）
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : -1; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : -1; }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define dump(...)
#define dumpel(v)
#define dump_list(v)
#define dump_mat(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) while (1) cout << "OLE"; }
#endif


//【ローリングハッシュ（列）】
/*
* Rolling_hash<STR>(STR s, bool reversible = false) : O(n)
*	列 s[0..n) で初期化する．reversible = true にすると逆順のハッシュも計算可能になる．
*	制約：STR は string，vector<T> など．ll 範囲の負数は扱えない．
*
* ull get(int l, int r) : O(1)
*	部分文字列 s[l..r) のハッシュ値を返す（空なら 0）
*
* ull get_rev(int l, int r) : O(1)
*	部分文字列 s[l..r) を反転した文字列のハッシュ値を返す（空なら 0）
*
* ull join(ull hs, ull ht, int len) : O(1)
*	ハッシュ値 hs をもつ s とハッシュ値 ht をもつ t[0..len) を連結した s+t のハッシュ値を返す．
*/
template <class STR>
class Rolling_hash {
	// 参考 : https://qiita.com/keymoon/items/11fac5627672a6d6a9f6

	//【方法】
	// 2^61 - 1 は十分大きい素数であるからローリングハッシュの法として適切である．
	// a, b < 2^61 - 1 とし，積 a b mod (2^61 - 1) を高速に計算できればよい．
	// 
	// まず a, b を上位と下位に分解し
	//		a = 2^31 ah + al, b = 2^31 bh + bl  (ah, bh < 2^30, al, bl < 2^31)
	// とする．これらの積をとると，
	//		a b
	//		= (2^31 ah + al)(2^31 bh + bl)
	//		= 2^62 ah bh + 2^31 (ah bl + bh al) + al bl
	// となる．2^61 ≡ 1 (mod 2^61 - 1) に注意してそれぞれの項を mod 2^61 - 1 で整理する．
	//
	// 第 1 項については，
	//		2^62 ah bh
	//		= 2 ah bh
	//		≦ 2 (2^30-1) (2^30-1)
	// となる．
	//
	// 第 2 項については，c := ah bl + bh al < 2^62 を上位と下位に分解し
	//		c = 2^30 ch + cl  (ch < 2^32, cl < 2^30)
	// とすると，
	//		2^31 c
	//		= 2^31 (2^30 ch + cl)
	//		= ch + 2^31 cl
	//		≦ (2^32-1) + 2^31 (2^30-1)
	// となる．
	//
	// 第 3 項については，
	//		al bl
	//		≦ (2^31-1) (2^31-1)
	// となる．
	// 
	// これらの和は
	//		2 ah bh + ch + 2^31 cl + al bl
	//		≦ 2 (2^30-1) (2^30-1) + (2^32-1) + 2^31 (2^30-1) + (2^31-1) (2^31-1)
	//		= 9223372030412324866 < 9223372036854775808 = 2^63 << 2^64
	// となるのでオーバーフローの心配はない．

	static constexpr ull MASK30 = (1ULL << 30) - 1;
	static constexpr ull MASK31 = (1ULL << 31) - 1;
	static constexpr ull MOD = (1ULL << 61) - 1; // 法（素数）

	// a mod (2^61 - 1) を返す．
	inline ull get_mod(ull a) const {
		ull ah = a >> 61, al = a & MOD;
		ull res = ah + al;
		if (res >= MOD) res -= MOD;
		return res;
	}

	// x ≡ a b mod (2^61 - 1) なる x < 2^63 を返す（ただし a, b < 2^61）
	inline ull mul(ull a, ull b) const {
		ull ah = a >> 31, al = a & MASK31;
		ull bh = b >> 31, bl = b & MASK31;

		ull c = ah * bl + bh * al;
		ull ch = c >> 30, cl = c & MASK30;

		ull term1 = 2 * ah * bh;
		ull term2 = ch + (cl << 31);
		ull term3 = al * bl;

		return term1 + term2 + term3; // < 2^63
	}

	static constexpr ull BASE = 1234567891011; // 適当な基数
	static constexpr ull SHIFT = 4295090752; // 適当なシフト

	// 列の長さ
	int n;

	// powB[i] : BASE^i
	vector<ull> powB;

	// v[i] : s[0..i) のハッシュ値 Σj∈[0..i) (s[j]+SHIFT) BASE^(i-1-j)
	// v_rev[i] : s[n-i..n) を反転した文字列のハッシュ値
	vector<ull> v, v_rev;

public:
	// 列 s[0..n) で初期化する．
	Rolling_hash(const STR& s, bool reversible = false) : n(sz(s)), powB(n + 1), v(n + 1) {
		// verify : https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ec

		powB[0] = 1;
		rep(i, n) powB[i + 1] = get_mod(mul(powB[i], BASE));

		rep(i, n) v[i + 1] = get_mod(mul(v[i], BASE) + (ull)s[i] + SHIFT);

		if (reversible) {
			v_rev.resize(n + 1);
			rep(i, n) v_rev[i + 1] = get_mod(mul(v_rev[i], BASE) + (ull)s[n - 1 - i] + SHIFT);
		}
	}
	Rolling_hash() : n(0) {}

	// s[l..r) のハッシュ値の取得
	ull get(int l, int r) const {
		// verify : https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ec

		chmax(l, 0); chmin(r, n);
		if (l >= r) return 0;

		return get_mod(v[r] + 4 * MOD - mul(v[l], powB[r - l]));
	}

	// s[l..r) を反転した文字列のハッシュ値の取得
	ull get_rev(int l, int r) {
		// verify : https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ec

		chmax(l, 0); chmin(r, n);
		if (l >= r) return 0;
		Assert(!v_rev.empty());

		// s[l, r) を反転した文字列は s_rev[n-r, n-l) に等しい．
		return get_mod(v_rev[n - l] + 4 * MOD - mul(v_rev[n - r], powB[r - l]));
	}

	// ハッシュ値 hs をもつ s とハッシュ値 ht をもつ t[0..len) を連結した s+t のハッシュ値を返す．
	ull join(ull hs, ull ht, int len) const {
		// verify : https://atcoder.jp/contests/abc284/tasks/abc284_f

		Assert(len <= n);
		return get_mod(ht + mul(hs, powB[len]));
	}
};


//【最長回文長（文字中心）】O(n)
/*
* s[0..n) の s[i] を中心とする最長回文の半径（(文字数 + 1) / 2）を r[i] に格納し r を返す．
* ここで回文の半径とは，(文字数 + 1) / 2 を意味する．
*/
template <class STR>
vi manacher(const STR& s) {
	// 参考 : https://snuke.hatenablog.com/entry/2014/12/02/235837
	// verify : https://judge.yosupo.jp/problem/enumerate_palindromes

	//【方法】
	// s[i] を中心とする最長回文の半径 j = r[i] が愚直に求まったとする．
	// すなわち s(i-j..i+j) が s[i] を中心とする最長回文である．
	// 
	// 各 k = [1..j) について，s[i-k] を中心とする最長回文 s(i-k-r[i-k]..i-k+r[i-k]) が
	// s(i-j+1..i+j-1) の部分文字列であれば，s[i±j] の影響を受けず
	// s[i] についての左右対称性より r[i+k] = r[i-k] と定まる．
	// その条件は，左端を比較して
	//		i - k - r[i-k] >= i - j + 1
	//		⇔ k + r[i-k] < j
	// である．このような結果の使い回しができる限り k を進め，次の i を i + k にする．
	// 
	// 使い回しができなくなったということは，s[i+k] を中心とする最長回文
	// s(i+k-r[i+k]..i+k+r[i+k]) が s(i-j+1..i+j-1) の部分文字列でないので，
	// 右端を比較することで
	//		i + k + r[i+k] > i + j - 1
	//		⇔ r[i+k] >= j - k
	// である．よって次の j は j - k にすればよい．

	int n = sz(s);
	vi r(n);

	int i = 0, j = 0;
	while (i < n) {
		while (i - j >= 0 && i + j < n && s[i - j] == s[i + j]) j++;
		r[i] = j;

		int k = 1;
		while (i - k >= 0 && k + r[i - k] < j) {
			r[i + k] = r[i - k];
			k++;
		}
		i += k;
		j -= k;
	}

	return r;
}


//【最長回文長】O(n)
/*
* s[0..n) の s[i] を中心とする最長回文の長さを lo[i] に格納し，
* s[i..i+1] を中心とする最長回文の長さを le[i] に格納する．
*
* 利用：【最長回文長（文字中心）】
*/
template <class STR>
void manacher(const STR& s, vi& lo, vi& le) {
	// 参考 : https://snuke.hatenablog.com/entry/2014/12/02/235837
	// verify : https://judge.yosupo.jp/problem/enumerate_palindromes

	int n = sz(s);
	lo.resize(n);
	le.resize(n - 1);

	STR s_riffled;
	s_riffled.resize(2 * n + 1);
	rep(i, n) s_riffled[2 * i + 1] = s[i];
	rep(i, n + 1) s_riffled[2 * i] = '$'; // '$' は s に含まれない文字

	vi r = manacher(s_riffled);

	rep(i, n) lo[i] = r[2 * i + 1] - 1;
	rep(i, n - 1) le[i] = r[2 * (i + 1)] - 1;
}


vector<unordered_map<ull, ll>> count_palindromes(const string& s) {
	int n = sz(s);

	Rolling_hash S(s, true);

	vi lo, le;
	manacher(s, lo, le);

	unordered_set<ull> hs;
	hs.insert(0);

	unordered_map<ull, pii> h_to_lr;
	vector<unordered_map<ull, ll>> cnt(n + 1);

	rep(i, n) {
		int r = lo[i] / 2;
		auto h = S.get(i - r, i + r + 1);
		dump(s.substr(i - r, 2 * r + 1));
		h_to_lr[h] = { i - r, i + r + 1 };
		cnt[2 * r + 1][h]++;
	}

	rep(i, n - 1) {
		int r = le[i] / 2;
		auto h = S.get(i - r + 1, i + r + 1);
		dump(s.substr(i - r + 1, 2 * r));
		h_to_lr[h] = { i - r + 1, i + r + 1 };
		cnt[2 * r][h]++;
	}

	repir(len, n, 1) {
		for (auto [h, c] : cnt[len]) {
			auto [l, r] = h_to_lr[h];

			if (len >= 2) {
				auto nh = S.get(l + 1, r - 1);
				h_to_lr[nh] = { l + 1, r - 1 };
				cnt[len - 2][nh] += c;
			}
		}
	}

	return cnt;
}


int main() {
//	input_from_file("input.txt");
//	output_to_file("output.txt");

	string s, t;
	cin >> s >> t;

	int n = sz(s), m = sz(t);

	auto cs = count_palindromes(s);
	auto ct = count_palindromes(t);
	dumpel(cs); dumpel(ct);

	ll res = 0;

	repi(len, 1, min(n, m)) {
		for (auto [h, c] : cs[len]) {
			res += c * ct[len][h];
		}
	}

	cout << res << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 18292
final_rank: 5

code_snippet: // #line 1 "library/Template/template.hpp"
#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define ALL(v) (v).begin(),(v).end()
#define UNIQUE(v) sort(ALL(v)),(v).erase(unique(ALL(v)),(v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v,x) int(lower_bound(ALL(v),(x))-(v).begin())
#define UB(v,x) int(upper_bound(ALL(v),(x))-(v).begin())

using ll=long long int;
using ull=unsigned long long;
using i128=__int128_t;
using u128=__uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template<typename T>inline bool chmax(T& a,T b){if(a<b){a=b;return 1;}return 0;}
template<typename T>inline bool chmin(T& a,T b){if(a>b){a=b;return 1;}return 0;}
template<typename T,typename U>T ceil(T x,U y){assert(y!=0); if(y<0)x=-x,y=-y; return (x>0?(x+y-1)/y:x/y);}
template<typename T,typename U>T floor(T x,U y){assert(y!=0); if(y<0)x=-x,y=-y; return (x>0?x/y:(x-y+1)/y);}
template<typename T>int popcnt(T x){return __builtin_popcountll(x);}
template<typename T>int topbit(T x){return (x==0?-1:63-__builtin_clzll(x));}
template<typename T>int lowbit(T x){return (x==0?-1:__builtin_ctzll(x));}
// #line 2 "library/Utility/fastio.hpp"
#include <unistd.h>

class FastIO{
    static constexpr int L=1<<16;
    char rdbuf[L];
    int rdLeft=0,rdRight=0;
    inline void reload(){
        int len=rdRight-rdLeft;
        memmove(rdbuf,rdbuf+rdLeft,len);
        rdLeft=0,rdRight=len;
        rdRight+=fread(rdbuf+len,1,L-len,stdin);
    }
    inline bool skip(){
        for(;;){
            while(rdLeft!=rdRight and rdbuf[rdLeft]<=' ')rdLeft++;
            if(rdLeft==rdRight){
                reload();
                if(rdLeft==rdRight)return false;
            }
            else break;
        }
        return true;
    }
    template<typename T,enable_if_t<is_integral<T>::value,int> =0>inline bool _read(T& x){
        if(!skip())return false;
        if(rdLeft+20>=rdRight)reload();
        bool neg=false;
        if(rdbuf[rdLeft]=='-'){
            neg=true;
            rdLeft++;
        }
        x=0;
        while(rdbuf[rdLeft]>='0' and rdLeft<rdRight){
            x=x*10+(neg?-(rdbuf[rdLeft++]^48):(rdbuf[rdLeft++]^48));
        }
        return true;
    }
    template<typename T,enable_if_t<is_floating_point<T>::value,int> =0>inline bool _read(T& x){
        if(!skip())return false;
        if(rdLeft+20>=rdRight)reload();
        bool neg=false;
        if(rdbuf[rdLeft]=='-'){
            neg=true;
            rdLeft++;
        }
        x=0;
        while(rdbuf[rdLeft]>='0' and rdbuf[rdLeft]<='9' and rdLeft<rdRight){
            x=x*10+(rdbuf[rdLeft++]^48);
        }
        if(rdbuf[rdLeft]!='.')return true;
        rdLeft++;
        T base=.1;
        while(rdbuf[rdLeft]>='0' and rdbuf[rdLeft]<='9' and rdLeft<rdRight){
            x+=base*(rdbuf[rdLeft++]^48);
            base*=.1;
        }
        if(neg)x=-x;
        return true;
    }
    inline bool _read(char& x){
        if(!skip())return false;
        if(rdLeft+1>=rdRight)reload();
        x=rdbuf[rdLeft++];
        return true;
    }
    inline bool _read(string& x){
        if(!skip())return false;
        for(;;){
            int pos=rdLeft;
            while(pos<rdRight and rdbuf[pos]>' ')pos++;
            x.append(rdbuf+rdLeft,pos-rdLeft);
            if(rdLeft==pos)break;
            rdLeft=pos;
            if(rdLeft==rdRight)reload();
            else break;
        }
        return true;
    }
    template<typename T>inline bool _read(vector<T>& v){
        for(auto& x:v){
            if(!_read(x))return false;
        }
        return true;
    }

    char wtbuf[L],tmp[50];
    int wtRight=0;
    inline void flush(){
        fwrite(wtbuf,1,wtRight,stdout);
        wtRight=0;
    }
    inline void _write(const char& x){
        if(wtRight>L-32)flush();
        wtbuf[wtRight++]=x;
    }
    inline void _write(const string& x){
        for(auto& c:x)_write(c);
    }
    template<typename T,enable_if_t<is_integral<T>::value,int> =0>inline void _write(T x){
        if(wtRight>L-32)flush();
        if(x==0){
            _write('0');
            return;
        }
        else if(x<0){
            _write('-');
            if (__builtin_expect(x == std::numeric_limits<T>::min(), 0)) {
                switch (sizeof(x)) {
                case 2: _write("32768"); return;
                case 4: _write("2147483648"); return;
                case 8: _write("9223372036854775808"); return;
                }
            }
            x=-x;
        }
        int pos=0;
        while(x!=0){
            tmp[pos++]=char((x%10)|48);
            x/=10;
        }
        rep(i,0,pos)wtbuf[wtRight+i]=tmp[pos-1-i];
        wtRight+=pos;
    }
    template<typename T>inline void _write(const vector<T>& v){
        rep(i,0,v.size()){
            if(i)_write(' ');
            _write(v[i]);
        }
    }
public:
    FastIO(){}
    ~FastIO(){flush();}
    inline void read(){}
    template <typename Head, typename... Tail>inline void read(Head& head,Tail&... tail){
        assert(_read(head));
        read(tail...);
    }
    template<bool ln=true,bool space=false>inline void write(){if(ln)_write('\n');}
    template <bool ln=true,bool space=false,typename Head, typename... Tail>inline void write(const Head& head,const Tail&... tail){
        if(space)_write(' ');
        _write(head);
        write<ln,true>(tail...);
    }
};

/**
 * @brief Fast IO
 */
// #line 3 "sol.cpp"


namespace Random{
    mt19937_64 randgen(chrono::steady_clock::now().time_since_epoch().count());
    using u64=unsigned long long;
    static u64 get(){
        return randgen();
    }
    template<typename T>static T get(T L){
        return get()%(L+1);
    }
    template<typename T>static T get(T L,T R){
        return get(R-L)+L;
    }
    double uniform(){
        return double(get(1000000000))/1000000000;
    }
    string str(int n){
        string ret;
        rep(i,0,n)ret+=get('a','z');
        return ret;
    }
    template<typename Iter>void shuffle(Iter first,Iter last){
        if(first==last)return;
        int len=1;
        for(auto it=first+1;it!=last;it++){
            len++;
            int j=get(0,len-1);
            if(j!=len-1)iter_swap(it,first+j);
        }
    }
    template<typename T>vector<T> select(int n,T L,T R){
        set<T> ret;
        while(ret.size()<n)ret.insert(get(L,R));
        return {ALL(ret)};
    }
};

struct RollingHash {
    using ull = unsigned long long;
    const ull MOD = 0x1fffffffffffffff;
    const ull base;
    vector<ull> hashed, power;

    static constexpr ull mask(ll a){ return (1ULL << a) - 1; }

    inline ull mul(ull a, ull b) const {
        __uint128_t ans = __uint128_t(a) * b;
        ans = (ans >> 61) + (ans & MOD);
        if(ans >= MOD) ans -= MOD;
        return ans;
    }

    static inline ull genbase(){return Random::get(ull(0x1fffffffffffffff));}
    RollingHash()=default;

    RollingHash(const string &s,ull base):base(base){
        ll n = s.size();
        hashed.assign(n + 1, 0);
        power.assign(n + 1, 0);
        power[0] = 1;
        for(ll i = 0; i < n; i++) {
            power[i + 1] = mul(power[i], base);
            hashed[i + 1] = mul(hashed[i], base) + s[i];
            if(hashed[i + 1] >= MOD) hashed[i + 1] -= MOD;
        }
    }

    ull get(ll l, ll r) const {
        ull ret = hashed[r] + MOD - mul(hashed[l], power[r - l]);
        if(ret >= MOD) ret -= MOD;
        return ret;
    }

    ull connect(ull h1, ull h2, ll h2len) const {
        ull ret = mul(h1, power[h2len]) + h2;
        if(ret >= MOD) ret -= MOD;
        return ret;
    }

    void connect(const string &s){
        ll n = hashed.size() - 1, m = s.size();
        hashed.resize(n + m + 1);
        power.resize(n + m + 1);
        for(ll i = n; i < n + m; i++) {
            power[i + 1] = mul(power[i], base);
            hashed[i + 1] = mul(hashed[i], base) + s[i - n];
            if(hashed[i + 1] >= MOD) hashed[i + 1] -= MOD;
        }
    }

    ll LCP(const RollingHash &b, ll l1, ll r1, ll l2, ll r2) {
        ll len = min(r1 - l1, r2 - l2);
        ll low = -1, high = len + 1;
        while(high - low > 1) {
            ll mid = (low + high) / 2;
            if(get(l1, l1 + mid) == b.get(l2, l2 + mid)) low = mid;
            else high = mid;
        }
        return low;
    }
};

template<typename T>struct PalindromicTree{
    struct Node{
        map<char,int> nxt;
        int link,len,id,cnt;
        Node(){}
        Node(int link,int len,int id,int cnt):link(link),len(len),id(id),cnt(cnt){}
    };
    T S;
    vector<Node> nodes;
    PalindromicTree(){}
    PalindromicTree(const T& S):S(S){
        nodes.push_back(Node(0,-1,-1,0));
        nodes.push_back(Node(0,0,-1,0));
        int cur=0;

        rep(i,0,SZ(S)){
            int k=find(i,cur);
            char c=S[i];
            if(nodes[k].nxt.count(c)){
                cur=nodes[k].nxt[c];
                nodes[cur].cnt++;
                continue;
            }
            nodes[k].nxt[c]=SZ(nodes);
            cur=SZ(nodes);
            nodes.push_back(Node(-1,nodes[k].len+2,i-nodes[k].len-1,1));
            if(nodes.back().len==1)nodes.back().link=1;
            else{
                int n=find(i,nodes[k].link);
                nodes.back().link=nodes[n].nxt[c];
            }
        }
    }
    vector<array<int,3>> get_freq(){
        vector<array<int,3>> ret;
        for(int i=SZ(nodes)-1;i>=2;i--){
            ret.push_back({nodes[i].len,nodes[i].id,nodes[i].cnt});
            nodes[nodes[i].link].cnt+=nodes[i].cnt;
        }
        return ret;
    }
private:
    int find(int last,int k)const{
        for(;;){
            int i=last-1-nodes[k].len;
            if(i>=0 and S[i]==S[last])break;
            k=nodes[k].link;
        }
        return k;
    }
};

FastIO io;
int main(){
    string S,T;
    io.read(S,T);

    using ull = unsigned long long;
    PalindromicTree<string> t1(S),t2(T);
    auto base=RollingHash::genbase();
    RollingHash rh1(S,base),rh2(T,base);
    auto f1=t1.get_freq();
    auto f2=t2.get_freq();

    map<ull,ll> mp;
    for(auto& [len,id,cnt]:f1){
        // cerr<<len<<' '<<id<<' '<<cnt<<'\n';
        mp[rh1.get(id,id+len)]+=cnt;
    }
    ll ret=0;
    for(auto& [len,id,cnt]:f2)ret+=mp[rh2.get(id,id+len)]*cnt;
    io.write(ret);
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 24968
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, n) for (int i = 0; i < (n); i++)
#define per(i, n) for (int i = (n)-1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define per2(i, l, r) for (int i = (r)-1; i >= (l); i--)
#define each(e, x) for (auto &e : x)
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define eb emplace_back
#define MM << ' ' <<
#define TT template <typename T>
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

TT void print(vector<T> v, T x = 0) {
    int n = sz(v);
    rep(i, n) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (n == 0) cout << '\n';
}

TT void printn(vector<T> v, T x = 0) {
    int n = sz(v);
    rep(i, n) cout << v[i] + x << '\n';
}

TT void rearrange(vector<T> &v) {
    sort(all(v));
    v.erase(unique(all(v)), end(v));
}

TT int lb(vector<T> &v, T x) { return lower_bound(all(v), x) - begin(v); }
TT int ub(vector<T> &v, T x) { return upper_bound(all(v), x) - begin(v); }

const int inf = (1 << 30) - 1;
const ll INF = (1LL << 60) - 1;

struct io_setup {
    io_setup() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
    }
} io_setup;

using ull = unsigned long long;
const ull mod = (1LL << 61) - 1;

namespace Hash {
ull getmod(ull x) {
    ull ret = (x >> 61) + (x & mod);
    if (ret >= mod) ret -= mod;
    return ret;
}

ull mul(ull x, ull y) {
    x = getmod(x), y = getmod(y);
    ull x1 = x >> 31;
    ull x2 = x & ((1LL << 31) - 1);
    ull y1 = y >> 31;
    ull y2 = y & ((1LL << 31) - 1);
    ull z = x1 * y2 + x2 * y1;
    ull z1 = z >> 30;
    ull z2 = z & ((1LL << 30) - 1);
    return getmod(x1 * y1 * 2 + x2 * y2 + z1 + (z2 << 31));
}
} // namespace Hash

template <typename T>
struct RollingHash {
    const int n;
    const ull b;
    vector<ull> h, p;

    RollingHash(const T &s, ull b = 887446835055281585) : n(sz(s)), b(b) {
        h.assign(n + 1, 0);
        p.assign(n + 1, 1);
        rep(i, n) {
            p[i + 1] = Hash::mul(p[i], b);
            h[i + 1] = Hash::mul(h[i], b) + s[i];
            if (h[i + 1] >= mod) h[i + 1] -= mod;
        }
    }

    ull gethash(int l, int r) {
        ull ret = h[r] + mod - Hash::mul(h[l], p[r - l]);
        if (ret >= mod) ret -= mod;
        return ret;
    }

    ull getallhash() { return h[n]; }
};

template <typename T>
vector<int> manachar(const T &s) {
    int n = sz(s);
    vector<int> ret(n);
    int i = 0, j = 0;
    while (i < n) {
        while (i - j >= 0 && i + j < n && s[i + j] == s[i - j]) j++;
        ret[i] = j;
        int k = 1;
        while (i - k >= 0 && k + ret[i - k] < j) ret[i + k] = ret[i - k], k++;
        i += k, j -= k;
    }
    return ret;
}

int main() {
    string S, T;
    cin >> S >> T;

    int N = sz(S), M = sz(T);

    RollingHash hashS(S), hashT(T);

    auto getPalindromeLen = [](string S) {
        int n = sz(S);
        string X = ".";
        rep(i, n) X += S[i], X += ".";
        auto a = manachar(X);
        // print(a);

        vector<vector<int>> ret(2, vector<int>(n));
        rep(i, n) {
            ret[0][i] = a[2 * i + 1] / 2;
            ret[1][i] = a[2 * i] / 2;
        }

        // rep(i, 2) print(ret[i]);

        return ret;
    };

    vector<vector<int>> ms = getPalindromeLen(S), mt = getPalindromeLen(T);

    auto solve = [&](vector<int> a, vector<int> b) {
        map<ull, int> mp;
        int K = 0;
        mp[0] = K++;
        vector<vector<int>> es;
        es.eb();

        vector<ll> cnt;
        cnt.eb(0);

        // print(a);

        rep(i, N) {
            int ok = 0, ng = a[i] + 1;
            while (abs(ok - ng) > 1) {
                int mid = (ok + ng) / 2;
                // cout << i MM i + mid << endl;
                ull x = hashS.gethash(i, i + mid);
                (mp.count(x) ? ok : ng) = mid;
            }

            // cout << i MM ok << endl;

            int p = mp[hashS.gethash(i, i + ok)];
            rep2(j, ok + 1, a[i] + 1) {
                ull x = hashS.gethash(i, i + j);
                es[p].eb(K);
                p = K;
                mp[x] = K++;
                es.eb();
                cnt.eb(0);
            }

            {
                ull x = hashS.gethash(i, i + a[i]);
                cnt[mp[x]]++;
            }
        }

        auto dfs1 = [&](auto &&dfs1, int now) -> ll {
            each(e, es[now]) {
                cnt[now] += dfs1(dfs1, e); //
            }
            return cnt[now];
        };

        dfs1(dfs1, 0);

        cnt[0] = 0;

        auto dfs2 = [&](auto &&dfs2, int now) -> void {
            each(e, es[now]) {
                cnt[e] += cnt[now];
                dfs2(dfs2, e);
            }
        };

        dfs2(dfs2, 0);

        ll ret = 0;

        rep(i, M) {
            int ok = 0, ng = b[i] + 1;
            while (abs(ok - ng) > 1) {
                int mid = (ok + ng) / 2;
                ull x = hashT.gethash(i, i + mid);
                (mp.count(x) ? ok : ng) = mid;
            }

            // cout << K MM i MM i + ok << endl;

            ret += cnt[mp[hashT.gethash(i, i + ok)]];
        }

        return ret;
    };

    ll ans = 0;
    rep(i, 2) ans += solve(ms[i], mt[i]);

    cout << ans << '\n';
}
accuracy: 1
time_ms: 280
memory_kb: 13768
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define inf 1000000007
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define fi first
#define se second
#define rep(i,n) for(int i = 0; i < (int)(n); ++i)
#define rrep(i,n) for(int i = (int)n-1; i >= 0; --i)
#define srep(i,a,b) for(int i = (int)a; i < (int)(b); ++i)
#define all(x) (x).begin(),(x).end()
#define SUM(v) accumulate(all(v), 0LL)
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
#define SZ(c) (int)(c).size()
template<typename T>
ostream& operator << (ostream& os, vector<T>& vec) {
    os << "{";
    for (int i = 0; i<(int)vec.size(); i++) {
        os << vec[i] << (i + 1 == (int)vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
// pair出力
template<typename T, typename U>
ostream& operator << (ostream& os, pair<T, U> pair_var) {
    os << "(" << pair_var.first << ", " << pair_var.second << ")";
    return os;
}
// map出力
template<typename T, typename U>
ostream& operator << (ostream& os, map<T, U>& map_var) {
    os << "{";
    for(auto itr = map_var.begin(); itr != map_var.end(); itr++){
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if(itr != map_var.end()) os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
// set 出力
template<typename T>
ostream& operator << (ostream& os, set<T>& set_var) {
    os << "{";
    for(auto itr = set_var.begin(); itr != set_var.end(); itr++){
        os << (*itr);
        ++itr;
        if(itr != set_var.end()) os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
// tuple 出力
template<int N,class Tuple>
void out(ostream &os,const Tuple &t){}
template<int N,class Tuple,class H,class ...Ts>
void out(ostream &os,const Tuple &t){
    if(N)os<<", ";
    os<<get<N>(t);
    out<N+1,Tuple,Ts...>(os,t);
}
template<class ...Ts>
ostream& operator<<(ostream &os, const tuple<Ts...> &t){
    os<<"(";
    out<0,tuple<Ts...>,Ts...>(os,t);
    os<<")";
    return os;
}
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
#ifdef LOCAL
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
    cerr << " " << H;
    debug_out(T...);
}
#define dbg(...) \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define dbg(...) (void(0))
#define dump(x) (void(0))
#endif
template<typename A, typename T>
std::enable_if_t<std::is_convertible<T, A>::value> fill(A& array, const T& val)
{
    array = val;
}
template<typename A, typename T>
std::enable_if_t<!std::is_convertible<T, A>::value> fill(A& array, const T& val)
{
    for (auto& a : array) {
        fill(a, val);
    }
}
template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}
template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
vector<int> iota(int n) {vector<int> a(n);iota(all(a), 0);return a;}
template <class T> T POW(T x, int n) {T res = 1;for(; n; n >>= 1, x *= x){if(n & 1) res *= x;}return res;}
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
ll allbit(ll n) { return (1LL << n) - 1; }
int popcount(signed t) { return __builtin_popcount(t); }
int popcount(ll t) { return __builtin_popcountll(t); }
bool ispow2(int i) { return i && (i & -i) == i; }


template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> void zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
}
template<class T> inline bool chmax(T &a, T b){
    if(a<b){
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmin(T &a, T b){
    if(a>b){
        a = b;
        return true;
    }
    return false;
}


std::vector<int> sa_naive(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n);
    std::iota(sa.begin(), sa.end(), 0);
    std::sort(sa.begin(), sa.end(), [&](int l, int r) {
        if (l == r) return false;
        while (l < n && r < n) {
            if (s[l] != s[r]) return s[l] < s[r];
            l++;
            r++;
        }
        return l == n;
    });
    return sa;
}

std::vector<int> sa_doubling(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n), rnk = s, tmp(n);
    std::iota(sa.begin(), sa.end(), 0);
    for (int k = 1; k < n; k *= 2) {
        auto cmp = [&](int x, int y) {
            if (rnk[x] != rnk[y]) return rnk[x] < rnk[y];
            int rx = x + k < n ? rnk[x + k] : -1;
            int ry = y + k < n ? rnk[y + k] : -1;
            return rx < ry;
        };
        std::sort(sa.begin(), sa.end(), cmp);
        tmp[sa[0]] = 0;
        for (int i = 1; i < n; i++) {
            tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0);
        }
        std::swap(tmp, rnk);
    }
    return sa;
}

// SA-IS, linear-time suffix array construction
// Reference:
// G. Nong, S. Zhang, and W. H. Chan,
// Two Efficient Algorithms for Linear Time Suffix Array Construction
template <int THRESHOLD_NAIVE = 10, int THRESHOLD_DOUBLING = 40>
std::vector<int> sa_is(const std::vector<int>& s, int upper) {
    int n = int(s.size());
    if (n == 0) return {};
    if (n == 1) return {0};
    if (n == 2) {
        if (s[0] < s[1]) {
            return {0, 1};
        } else {
            return {1, 0};
        }
    }
    if (n < THRESHOLD_NAIVE) {
        return sa_naive(s);
    }
    if (n < THRESHOLD_DOUBLING) {
        return sa_doubling(s);
    }

    std::vector<int> sa(n);
    std::vector<bool> ls(n);
    for (int i = n - 2; i >= 0; i--) {
        ls[i] = (s[i] == s[i + 1]) ? ls[i + 1] : (s[i] < s[i + 1]);
    }
    std::vector<int> sum_l(upper + 1), sum_s(upper + 1);
    for (int i = 0; i < n; i++) {
        if (!ls[i]) {
            sum_s[s[i]]++;
        } else {
            sum_l[s[i] + 1]++;
        }
    }
    for (int i = 0; i <= upper; i++) {
        sum_s[i] += sum_l[i];
        if (i < upper) sum_l[i + 1] += sum_s[i];
    }

    auto induce = [&](const std::vector<int>& lms) {
        std::fill(sa.begin(), sa.end(), -1);
        std::vector<int> buf(upper + 1);
        std::copy(sum_s.begin(), sum_s.end(), buf.begin());
        for (auto d : lms) {
            if (d == n) continue;
            sa[buf[s[d]]++] = d;
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        sa[buf[s[n - 1]]++] = n - 1;
        for (int i = 0; i < n; i++) {
            int v = sa[i];
            if (v >= 1 && !ls[v - 1]) {
                sa[buf[s[v - 1]]++] = v - 1;
            }
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        for (int i = n - 1; i >= 0; i--) {
            int v = sa[i];
            if (v >= 1 && ls[v - 1]) {
                sa[--buf[s[v - 1] + 1]] = v - 1;
            }
        }
    };

    std::vector<int> lms_map(n + 1, -1);
    int m = 0;
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) {
            lms_map[i] = m++;
        }
    }
    std::vector<int> lms;
    lms.reserve(m);
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) {
            lms.push_back(i);
        }
    }

    induce(lms);

    if (m) {
        std::vector<int> sorted_lms;
        sorted_lms.reserve(m);
        for (int v : sa) {
            if (lms_map[v] != -1) sorted_lms.push_back(v);
        }
        std::vector<int> rec_s(m);
        int rec_upper = 0;
        rec_s[lms_map[sorted_lms[0]]] = 0;
        for (int i = 1; i < m; i++) {
            int l = sorted_lms[i - 1], r = sorted_lms[i];
            int end_l = (lms_map[l] + 1 < m) ? lms[lms_map[l] + 1] : n;
            int end_r = (lms_map[r] + 1 < m) ? lms[lms_map[r] + 1] : n;
            bool same = true;
            if (end_l - l != end_r - r) {
                same = false;
            } else {
                while (l < end_l) {
                    if (s[l] != s[r]) {
                        break;
                    }
                    l++;
                    r++;
                }
                if (l == n || s[l] != s[r]) same = false;
            }
            if (!same) rec_upper++;
            rec_s[lms_map[sorted_lms[i]]] = rec_upper;
        }

        auto rec_sa =
            sa_is<THRESHOLD_NAIVE, THRESHOLD_DOUBLING>(rec_s, rec_upper);

        for (int i = 0; i < m; i++) {
            sorted_lms[i] = lms[rec_sa[i]];
        }
        induce(sorted_lms);
    }
    return sa;
}

std::vector<int> suffix_array(const std::string& s) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return sa_is(s2, 255);
}

template <class T>
std::vector<int> lcp_array(const std::vector<T>& s,
                           const std::vector<int>& sa) {
    int n = int(s.size());
    assert(n >= 1);
    std::vector<int> rnk(n);
    for (int i = 0; i < n; i++) {
        rnk[sa[i]] = i;
    }
    std::vector<int> lcp(n - 1);
    int h = 0;
    for (int i = 0; i < n; i++) {
        if (h > 0) h--;
        if (rnk[i] == 0) continue;
        int j = sa[rnk[i] - 1];
        for (; j + h < n && i + h < n; h++) {
            if (s[j + h] != s[i + h]) break;
        }
        lcp[rnk[i] - 1] = h;
    }
    return lcp;
}

std::vector<int> lcp_array(const std::string& s, const std::vector<int>& sa) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return lcp_array(s2, sa);
}

template<typename T> class segtree {
private:
    int n,sz,h; vector<T> node, lazy_update, lazy_add; vector<bool> lazyFlag;
public:
    segtree(vector<T> v) : n(1), sz((int)v.size()), h(0){
        while(n < sz) n *= 2, h++;
        node.resize(2*n, 0);
        lazy_update.resize(2*n, 0); lazyFlag.resize(2*n, false);
        lazy_add.resize(2*n, 0);
        for(int i = 0; i < sz; i++) node[i+n] = v[i];
        for(int i=n-1; i>=1; i--) node[i] = node[2*i] + node[2*i+1];
    }
    void eval(int k) {
        if(lazyFlag[k]){
            lazy_update[k] += lazy_add[k];
            node[k] = lazy_update[k];
            if(k < n) {
                lazy_add[2*k] = lazy_add[2*k+1] = 0;
                lazy_update[2*k] = lazy_update[2*k+1] = lazy_update[k] / 2;
                lazyFlag[2*k] = lazyFlag[2*k+1] = true;
            }
            lazy_add[k] = 0, lazyFlag[k] = false;
        }else if(lazy_add[k] != 0){
            node[k] += lazy_add[k];
            if(k < n){
                lazy_add[2*k] += lazy_add[k] / 2; lazy_add[2*k+1] += lazy_add[k] / 2;
            }
            lazy_add[k] = 0;
        }
    }
    void update(int a, int b, T x, int k=1, int l=0, int r=-1) {
        if(r < 0) r = n;
        eval(k);
        if(b <= l || r <= a) return;
        if(a <= l && r <= b){
            lazy_update[k] = x*(r-l); lazyFlag[k] = true; eval(k);
        }else{
            update(a, b, x, 2*k, l, (l+r)/2); update(a, b, x, 2*k+1, (l+r)/2, r);
            node[k] = node[2*k] + node[2*k+1];
        }
    }
    void add(int a, int b, T x, int k=1, int l=0, int r=-1){
        if(r < 0) r = n;
        eval(k);
        if(b <= l || r <= a) return;
        if(a <= l && r <= b){
            lazy_add[k] += x*(r-l); eval(k);
        }else{
            add(a, b, x, 2*k, l, (l+r)/2); add(a, b, x, 2*k+1, (l+r)/2, r);
            node[k] = node[2*k] + node[2*k+1];
        }
    }
    T query(int a, int b) {
        a += n, b += n - 1;
        for(int i = h; i > 0; i--) eval(a >> i), eval(b >> i);
        b++;
        T res1 = 0, res2 = 0;
        while(a < b) {
            if(a & 1) eval(a), res1 += node[a++];
            if(b & 1) eval(--b), res2 += node[b];
            a >>= 1, b >>= 1;
        }
        return res1 + res2;
    }
    void print(){for(int i = 0; i < sz; i++)cout<<query(i,i+1)<< " ";cout<<endl;}
};




//iを中心とする最長の回文の半径をR[i]に格納(O(n))
// abaab を $a$b$a$a$b$ みたいにすると偶数長のもの求めることが可能
void manacher(const string& S,vector<int>& res)
{
    int sz = (int)S.size(), i = 0, j = 0, k;
    res.resize(sz);
    while(i < sz){
        while(i-j >= 0 && i+j < sz && S[i-j] == S[i+j]) j++;
        res[i] = j, k = 1;
        while(i-k >= 0 && i+k < sz && k+res[i-k] < j){
            res[i+k] = res[i-k], k++;
        }
        i += k; j -= k;
    }
}


int main(){
    STR(s,t);
    string Q;
    rep(i,s.size()){
        Q.push_back('$');
        Q.push_back(s[i]);
    }
    Q.push_back('$');
    Q.push_back('|');
    int T = Q.size();
    rep(i,t.size()){
        Q.push_back('$');
        Q.push_back(t[i]);
    }
    Q.push_back('$');
    vector<int> mana;
    manacher(Q,mana);
    // cerr << mana << endl;
    int n = Q.size();
    
    auto sa = suffix_array(Q);
    auto lcp = lcp_array(Q,sa);
    ll res = 0;
    vector<ll> ppp(30000);
    segtree<ll> segS(ppp);
    segtree<ll> segT(ppp);
    // cerr << Q << endl;
    for(int i=0;i<sa.size();i++){
        int id = sa[i];
        int LCP = inf;
        if(i!=0)chmin(LCP,lcp[i-1]);
        if(Q[id]=='$'){
            int len = LCP/2;    
            segS.update(len+1,30000,0);
            segT.update(len+1,30000,0);
        }else{
            int len = (LCP+1)/2;
            segS.update(len+1,30000,0);
            segT.update(len+1,30000,0);
        }
        if(Q[id]=='|')continue;
        if(id<T){
            int len = mana[id]/2;
            res += segT.query(1,len+1);
            segS.add(0,len+1,1);
        }else{
            int len = mana[id]/2;
            res += segS.query(1,len+1);
            segT.add(0,len+1,1);
        }
        // cerr << id << endl;
        // cerr << Q.substr(id) << endl;
        // dbg(res);
    }
    cout << res << endl;

    
    return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 9928
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define inf 1000000007
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define fi first
#define se second
#define rep(i,n) for(int i = 0; i < (int)(n); ++i)
#define rrep(i,n) for(int i = (int)n-1; i >= 0; --i)
#define srep(i,a,b) for(int i = (int)a; i < (int)(b); ++i)
#define all(x) (x).begin(),(x).end()
#define SUM(v) accumulate(all(v), 0LL)
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
#define SZ(c) (int)(c).size()
template<typename T>
ostream& operator << (ostream& os, vector<T>& vec) {
    os << "{";
    for (int i = 0; i<(int)vec.size(); i++) {
        os << vec[i] << (i + 1 == (int)vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
// pair出力
template<typename T, typename U>
ostream& operator << (ostream& os, pair<T, U> pair_var) {
    os << "(" << pair_var.first << ", " << pair_var.second << ")";
    return os;
}
// map出力
template<typename T, typename U>
ostream& operator << (ostream& os, map<T, U>& map_var) {
    os << "{";
    for(auto itr = map_var.begin(); itr != map_var.end(); itr++){
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if(itr != map_var.end()) os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
// set 出力
template<typename T>
ostream& operator << (ostream& os, set<T>& set_var) {
    os << "{";
    for(auto itr = set_var.begin(); itr != set_var.end(); itr++){
        os << (*itr);
        ++itr;
        if(itr != set_var.end()) os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
// tuple 出力
template<int N,class Tuple>
void out(ostream &os,const Tuple &t){}
template<int N,class Tuple,class H,class ...Ts>
void out(ostream &os,const Tuple &t){
    if(N)os<<", ";
    os<<get<N>(t);
    out<N+1,Tuple,Ts...>(os,t);
}
template<class ...Ts>
ostream& operator<<(ostream &os, const tuple<Ts...> &t){
    os<<"(";
    out<0,tuple<Ts...>,Ts...>(os,t);
    os<<")";
    return os;
}
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
#ifdef LOCAL
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
    cerr << " " << H;
    debug_out(T...);
}
#define dbg(...) \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define dbg(...) (void(0))
#define dump(x) (void(0))
#endif
template<typename A, typename T>
std::enable_if_t<std::is_convertible<T, A>::value> fill(A& array, const T& val)
{
    array = val;
}
template<typename A, typename T>
std::enable_if_t<!std::is_convertible<T, A>::value> fill(A& array, const T& val)
{
    for (auto& a : array) {
        fill(a, val);
    }
}
template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}
template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
vector<int> iota(int n) {vector<int> a(n);iota(all(a), 0);return a;}
template <class T> T POW(T x, int n) {T res = 1;for(; n; n >>= 1, x *= x){if(n & 1) res *= x;}return res;}
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
ll allbit(ll n) { return (1LL << n) - 1; }
int popcount(signed t) { return __builtin_popcount(t); }
int popcount(ll t) { return __builtin_popcountll(t); }
bool ispow2(int i) { return i && (i & -i) == i; }


template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> void zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
}
template<class T> inline bool chmax(T &a, T b){
    if(a<b){
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmin(T &a, T b){
    if(a>b){
        a = b;
        return true;
    }
    return false;
}


std::vector<int> sa_naive(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n);
    std::iota(sa.begin(), sa.end(), 0);
    std::sort(sa.begin(), sa.end(), [&](int l, int r) {
        if (l == r) return false;
        while (l < n && r < n) {
            if (s[l] != s[r]) return s[l] < s[r];
            l++;
            r++;
        }
        return l == n;
    });
    return sa;
}

std::vector<int> sa_doubling(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n), rnk = s, tmp(n);
    std::iota(sa.begin(), sa.end(), 0);
    for (int k = 1; k < n; k *= 2) {
        auto cmp = [&](int x, int y) {
            if (rnk[x] != rnk[y]) return rnk[x] < rnk[y];
            int rx = x + k < n ? rnk[x + k] : -1;
            int ry = y + k < n ? rnk[y + k] : -1;
            return rx < ry;
        };
        std::sort(sa.begin(), sa.end(), cmp);
        tmp[sa[0]] = 0;
        for (int i = 1; i < n; i++) {
            tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0);
        }
        std::swap(tmp, rnk);
    }
    return sa;
}

// SA-IS, linear-time suffix array construction
// Reference:
// G. Nong, S. Zhang, and W. H. Chan,
// Two Efficient Algorithms for Linear Time Suffix Array Construction
template <int THRESHOLD_NAIVE = 10, int THRESHOLD_DOUBLING = 40>
std::vector<int> sa_is(const std::vector<int>& s, int upper) {
    int n = int(s.size());
    if (n == 0) return {};
    if (n == 1) return {0};
    if (n == 2) {
        if (s[0] < s[1]) {
            return {0, 1};
        } else {
            return {1, 0};
        }
    }
    if (n < THRESHOLD_NAIVE) {
        return sa_naive(s);
    }
    if (n < THRESHOLD_DOUBLING) {
        return sa_doubling(s);
    }

    std::vector<int> sa(n);
    std::vector<bool> ls(n);
    for (int i = n - 2; i >= 0; i--) {
        ls[i] = (s[i] == s[i + 1]) ? ls[i + 1] : (s[i] < s[i + 1]);
    }
    std::vector<int> sum_l(upper + 1), sum_s(upper + 1);
    for (int i = 0; i < n; i++) {
        if (!ls[i]) {
            sum_s[s[i]]++;
        } else {
            sum_l[s[i] + 1]++;
        }
    }
    for (int i = 0; i <= upper; i++) {
        sum_s[i] += sum_l[i];
        if (i < upper) sum_l[i + 1] += sum_s[i];
    }

    auto induce = [&](const std::vector<int>& lms) {
        std::fill(sa.begin(), sa.end(), -1);
        std::vector<int> buf(upper + 1);
        std::copy(sum_s.begin(), sum_s.end(), buf.begin());
        for (auto d : lms) {
            if (d == n) continue;
            sa[buf[s[d]]++] = d;
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        sa[buf[s[n - 1]]++] = n - 1;
        for (int i = 0; i < n; i++) {
            int v = sa[i];
            if (v >= 1 && !ls[v - 1]) {
                sa[buf[s[v - 1]]++] = v - 1;
            }
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        for (int i = n - 1; i >= 0; i--) {
            int v = sa[i];
            if (v >= 1 && ls[v - 1]) {
                sa[--buf[s[v - 1] + 1]] = v - 1;
            }
        }
    };

    std::vector<int> lms_map(n + 1, -1);
    int m = 0;
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) {
            lms_map[i] = m++;
        }
    }
    std::vector<int> lms;
    lms.reserve(m);
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) {
            lms.push_back(i);
        }
    }

    induce(lms);

    if (m) {
        std::vector<int> sorted_lms;
        sorted_lms.reserve(m);
        for (int v : sa) {
            if (lms_map[v] != -1) sorted_lms.push_back(v);
        }
        std::vector<int> rec_s(m);
        int rec_upper = 0;
        rec_s[lms_map[sorted_lms[0]]] = 0;
        for (int i = 1; i < m; i++) {
            int l = sorted_lms[i - 1], r = sorted_lms[i];
            int end_l = (lms_map[l] + 1 < m) ? lms[lms_map[l] + 1] : n;
            int end_r = (lms_map[r] + 1 < m) ? lms[lms_map[r] + 1] : n;
            bool same = true;
            if (end_l - l != end_r - r) {
                same = false;
            } else {
                while (l < end_l) {
                    if (s[l] != s[r]) {
                        break;
                    }
                    l++;
                    r++;
                }
                if (l == n || s[l] != s[r]) same = false;
            }
            if (!same) rec_upper++;
            rec_s[lms_map[sorted_lms[i]]] = rec_upper;
        }

        auto rec_sa =
            sa_is<THRESHOLD_NAIVE, THRESHOLD_DOUBLING>(rec_s, rec_upper);

        for (int i = 0; i < m; i++) {
            sorted_lms[i] = lms[rec_sa[i]];
        }
        induce(sorted_lms);
    }
    return sa;
}

std::vector<int> suffix_array(const std::string& s) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return sa_is(s2, 255);
}

template <class T>
std::vector<int> lcp_array(const std::vector<T>& s,
                           const std::vector<int>& sa) {
    int n = int(s.size());
    assert(n >= 1);
    std::vector<int> rnk(n);
    for (int i = 0; i < n; i++) {
        rnk[sa[i]] = i;
    }
    std::vector<int> lcp(n - 1);
    int h = 0;
    for (int i = 0; i < n; i++) {
        if (h > 0) h--;
        if (rnk[i] == 0) continue;
        int j = sa[rnk[i] - 1];
        for (; j + h < n && i + h < n; h++) {
            if (s[j + h] != s[i + h]) break;
        }
        lcp[rnk[i] - 1] = h;
    }
    return lcp;
}

std::vector<int> lcp_array(const std::string& s, const std::vector<int>& sa) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return lcp_array(s2, sa);
}

template<typename T> class segtree {
private:
    int n,sz,h; vector<T> node, lazy_update, lazy_add; vector<bool> lazyFlag;
public:
    segtree(vector<T> v) : n(1), sz((int)v.size()), h(0){
        while(n < sz) n *= 2, h++;
        node.resize(2*n, 0);
        lazy_update.resize(2*n, 0); lazyFlag.resize(2*n, false);
        lazy_add.resize(2*n, 0);
        for(int i = 0; i < sz; i++) node[i+n] = v[i];
        for(int i=n-1; i>=1; i--) node[i] = node[2*i] + node[2*i+1];
    }
    void eval(int k) {
        if(lazyFlag[k]){
            lazy_update[k] += lazy_add[k];
            node[k] = lazy_update[k];
            if(k < n) {
                lazy_add[2*k] = lazy_add[2*k+1] = 0;
                lazy_update[2*k] = lazy_update[2*k+1] = lazy_update[k] / 2;
                lazyFlag[2*k] = lazyFlag[2*k+1] = true;
            }
            lazy_add[k] = 0, lazyFlag[k] = false;
        }else if(lazy_add[k] != 0){
            node[k] += lazy_add[k];
            if(k < n){
                lazy_add[2*k] += lazy_add[k] / 2; lazy_add[2*k+1] += lazy_add[k] / 2;
            }
            lazy_add[k] = 0;
        }
    }
    void update(int a, int b, T x, int k=1, int l=0, int r=-1) {
        if(r < 0) r = n;
        eval(k);
        if(b <= l || r <= a) return;
        if(a <= l && r <= b){
            lazy_update[k] = x*(r-l); lazyFlag[k] = true; eval(k);
        }else{
            update(a, b, x, 2*k, l, (l+r)/2); update(a, b, x, 2*k+1, (l+r)/2, r);
            node[k] = node[2*k] + node[2*k+1];
        }
    }
    void add(int a, int b, T x, int k=1, int l=0, int r=-1){
        if(r < 0) r = n;
        eval(k);
        if(b <= l || r <= a) return;
        if(a <= l && r <= b){
            lazy_add[k] += x*(r-l); eval(k);
        }else{
            add(a, b, x, 2*k, l, (l+r)/2); add(a, b, x, 2*k+1, (l+r)/2, r);
            node[k] = node[2*k] + node[2*k+1];
        }
    }
    T query(int a, int b) {
        a += n, b += n - 1;
        for(int i = h; i > 0; i--) eval(a >> i), eval(b >> i);
        b++;
        T res1 = 0, res2 = 0;
        while(a < b) {
            if(a & 1) eval(a), res1 += node[a++];
            if(b & 1) eval(--b), res2 += node[b];
            a >>= 1, b >>= 1;
        }
        return res1 + res2;
    }
    void print(){for(int i = 0; i < sz; i++)cout<<query(i,i+1)<< " ";cout<<endl;}
};




//iを中心とする最長の回文の半径をR[i]に格納(O(n))
// abaab を $a$b$a$a$b$ みたいにすると偶数長のもの求めることが可能
void manacher(const string& S,vector<int>& res)
{
    int sz = (int)S.size(), i = 0, j = 0, k;
    res.resize(sz);
    while(i < sz){
        while(i-j >= 0 && i+j < sz && S[i-j] == S[i+j]) j++;
        res[i] = j, k = 1;
        while(i-k >= 0 && i+k < sz && k+res[i-k] < j){
            res[i+k] = res[i-k], k++;
        }
        i += k; j -= k;
    }
}


int main(){
    STR(s,t);
    string Q;
    rep(i,s.size()){
        Q.push_back('$');
        Q.push_back(s[i]);
    }
    Q.push_back('$');
    Q.push_back('|');
    int T = Q.size();
    rep(i,t.size()){
        Q.push_back('$');
        Q.push_back(t[i]);
    }
    Q.push_back('$');
    vector<int> mana;
    manacher(Q,mana);
    // cerr << mana << endl;
    int n = Q.size();
    
    auto sa = suffix_array(Q);
    auto lcp = lcp_array(Q,sa);
    ll res = 0;
    vector<ll> ppp(30000);
    segtree<ll> segS(ppp);
    segtree<ll> segT(ppp);
    // cerr << Q << endl;
    for(int i=0;i<sa.size();i++){
        int id = sa[i];
        int LCP = inf;
        if(i!=0)chmin(LCP,lcp[i-1]);
        if(Q[id]=='$'){
            int len = LCP/2;    
            segS.update(len+1,30000,0);
            segT.update(len+1,30000,0);
        }else{
            int len = (LCP+1)/2;
            segS.update(len+1,30000,0);
            segT.update(len+1,30000,0);
        }
        if(id<T){
            int len = mana[id]/2;
            res += segT.query(1,len+1);
            segS.add(0,len+1,1);
        }else{
            int len = mana[id]/2;
            res += segS.query(1,len+1);
            segT.add(0,len+1,1);
        }
        // cerr << id << endl;
        // cerr << Q.substr(id) << endl;
        // dbg(res);
    }
    cout << res << endl;

    
    return 0;
}
accuracy: 0.08333333333333333
time_ms: 160
memory_kb: 9680
final_rank: 19

code_snippet: #include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

/* macro */

#define rep(i, a, n) for (int i = (int)(a); i < (int)(n); i++)
#define rrep(i, a, n) for (int i = ((int)(n)-1); i >= (int)(a); i--)
#define Rep(i, a, n) for (i64 i = (i64)(a); i < (i64)(n); i++)
#define RRep(i, a, n) for (i64 i = ((i64)(n)-i64(1)); i >= (i64)(a); i--)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

/* macro end */

/* template */

namespace ebi {

#ifdef LOCAL
#define debug(...)                                                      \
    std::cerr << "LINE: " << __LINE__ << "  [" << #__VA_ARGS__ << "]:", \
        debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif

void debug_out() { std::cerr << std::endl; }

template <typename Head, typename... Tail>
void debug_out(Head h, Tail... t) {
    std::cerr << " " << h;
    if (sizeof...(t) > 0) std::cout << " :";
    debug_out(t...);
}

template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &os, const std::pair<T1, T2> &pa) {
    return os << pa.first << " " << pa.second;
}

template <typename T1, typename T2>
std::istream &operator>>(std::istream &os, std::pair<T1, T2> &pa) {
    return os >> pa.first >> pa.second;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
    for (std::size_t i = 0; i < vec.size(); i++)
        os << vec[i] << (i + 1 == vec.size() ? "" : " ");
    return os;
}

template <typename T>
std::istream &operator>>(std::istream &os, std::vector<T> &vec) {
    for (T &e : vec) std::cin >> e;
    return os;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::optional<T> &opt) {
    if (opt) {
        os << opt.value();
    } else {
        os << "invalid value";
    }
    return os;
}

using std::size_t;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;

template <class T, T init>
auto make_vector(int n) {
    return std::vector<T>(n, init);
}

template <class T, T init, typename Head, typename... Tail>
auto make_vector(Head n, Tail... ts) {
    return std::vector(n, make_vector<T, init>(ts...));
}

template <class T>
inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

template <class T>
inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template <class T>
T pow(T x, i64 n) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}

template <class T>
T mod_pow(T x, i64 n, i64 mod) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = (res * x) % mod;
        x = (x * x) % mod;
        n >>= 1;
    }
    return res;
}

template <class T>
T scan() {
    T val;
    std::cin >> val;
    return val;
}

template <class T>
struct Edge {
    int to;
    T cost;
    Edge(int _to, T _cost = 1) : to(_to), cost(_cost) {}
};

template <class T>
struct Graph : std::vector<std::vector<Edge<T>>> {
    using std::vector<std::vector<Edge<T>>>::vector;
    void add_edge(int u, int v, T w, bool directed = false) {
        (*this)[u].emplace_back(v, w);
        if (directed) return;
        (*this)[v].emplace_back(u, w);
    }
};

struct graph : std::vector<std::vector<int>> {
    using std::vector<std::vector<int>>::vector;
    void add_edge(int u, int v, bool directed = false) {
        (*this)[u].emplace_back(v);
        if (directed) return;
        (*this)[v].emplace_back(u);
    }
};

constexpr i64 LNF = std::numeric_limits<i64>::max() / 4;

constexpr int INF = std::numeric_limits<int>::max() / 2;

const std::vector<int> dy = {1, 0, -1, 0, 1, 1, -1, -1};
const std::vector<int> dx = {0, 1, 0, -1, 1, -1, 1, -1};

}  // namespace ebi

namespace ebi {

struct random_number_generator_64 {
private:
    using u64 = std::uint64_t;
    std::random_device rnd;
    std::mt19937_64 mt;
public:
    random_number_generator_64() : mt(rnd()) { }

    u64 get(u64 a, u64 b) {
        std::uniform_int_distribution<u64> dist(a, b-1);
        return dist(mt);
    }
};

}

namespace ebi {

using u64 = std::uint64_t;
const u64 mod = (1ull << 61) - 1;
const u64 MASK31 = (1ull << 31) - 1;
const u64 MASK30 = (1ull << 30) - 1;

u64 safe_mul(const u64 &a, const u64 &b) {
    u64 au = a >> 31, ad = a & MASK31;
    u64 bu = b >> 31, bd = b & MASK31;
    u64 mid = ad * bu + au * bd;
    u64 midu = mid >> 30;
    u64 midd = mid & MASK30;
    return (au * bu * 2 + midu + (midd << 31) + ad * bd);
}

u64 safe_mod(const u64 &a) {
    u64 au = a >> 61;
    u64 ad = a & mod;
    u64 res = au + ad;
    if (res >= mod) res -= mod;
    return res;
}

}  // namespace ebi

/*
    reference: https://qiita.com/keymoon/items/11fac5627672a6d6a9f6
*/

namespace ebi {

template <int n>
struct rolling_hash {
   private:
    using u64 = std::uint64_t;
    const u64 h = 100;
    const u64 buffer = mod * 4;

   public:
    rolling_hash(const std::string &s) : sz(s.size()) {
        assert(int(base.size()) == n && n > 0);
        base_pow.resize(n);
        hash.resize(n);
        for (int i = 0; i < n; ++i) {
            base_pow[i].reserve(sz + 1);
            base_pow[i].emplace_back(1);
            hash[i].reserve(sz + 1);
            hash[i].emplace_back(0);
            for (const auto &c : s) {
                hash[i].emplace_back(
                    safe_mod(safe_mul(hash[i].back(), base[i]) + c + h));
                base_pow[i].emplace_back(
                    safe_mod(safe_mul(base_pow[i].back(), base[i])));
            }
        }
    }

    // [l, r)

    std::vector<u64> get_hash(int l, int r) const {
        std::vector<u64> ret(n);
        for (int i = 0; i < n; ++i) {
            ret[i] = safe_mod(hash[i][r] + buffer -
                              safe_mul(hash[i][l], base_pow[i][r - l]));
        }
        return ret;
    }

    std::vector<u64> get_hash(const std::string &str, int l = 0,
                              int r = -1) const {
        if (r < 0) r = int(str.size());
        std::vector<u64> res(n, 0);
        for (int i = 0; i < n; ++i) {
            for (int j = l; j < r; ++j) {
                res[i] = safe_mod(safe_mul(res[i], base[i]) + str[i] + h);
            }
        }
        return res;
    }

    static void set_base() {
        random_number_generator_64 rnd;
        base.resize(n);
        for (int i = 0; i < n; ++i) {
            base[i] = rnd.get(0, (1UL << 61) - 1);
        }
    }

   private:
    size_t sz;
    std::vector<std::vector<u64>> base_pow;
    std::vector<std::vector<u64>> hash;

   public:
    static std::vector<u64> base;
};

template <int n>
std::vector<std::uint64_t> rolling_hash<n>::base{12345, 10000000};

}  // namespace ebi

namespace ebi {

struct palindromic_tree {
private:
    using i64 = std::int64_t;
    struct Node {
        std::map<char, int> edges;
        int len; // 回文の長さ
        int num = 0;
        int suffix_link = 0;
        std::vector<u64> hash;
    };
public:
    palindromic_tree(const std::string &str) : rh(str) {
        tree.resize(2);
        tree[0].len = -1;
        tree[1].len = 0;
        for(auto c: str) {
            add_char(c);
        }
    }

    // 末尾に x を追加し、末尾を使った最大の長さを返す。
    int add_char(char x) {
        s.push_back(x);
        int pos = s.size() - 1;
        int now = last_idx;
        while(true) {
            int len = tree[now].len;
            if(0 <= pos - len - 1 && s[pos - len - 1] == x) {
                break;
            }
            now = tree[now].suffix_link;
        }
        if(tree[now].edges.find(x) != tree[now].edges.end()) {
            last_idx = tree[now].edges[x];
            tree[last_idx].num++;
            return tree[last_idx].len;
        }
        last_idx = tree.size();
        tree[now].edges[x] = last_idx;
        Node node;
        node.len = tree[now].len + 2;
        node.num = 1;
        node.hash = rh.get_hash(pos+1-node.len, pos+1);
        if(node.len == 1) {
            node.suffix_link = 1;
            tree.emplace_back(node);
            return node.len;
        }
        while(true) {
            now = tree[now].suffix_link;
            int len = tree[now].len;
            if(0 <= pos - 1 - len && s[pos - 1 - len] == x) break;
        }
        node.suffix_link = tree[now].edges[x];
        tree.emplace_back(node);
        return node.len;
    }

    int count_types() {
        return (int)tree.size() - 2;
    }

    i64 count_num() {
        if(sum != -1) return sum;
        sum = 0;
        for(int i = tree.size() - 1; i >= 2; i--) {
            int suffix_link = tree[i].suffix_link;
            sum += tree[i].num;
            tree[suffix_link].num += tree[i].num;
        }
        return sum;
    }

    std::map<std::vector<u64>, i64> get_map() {
        std::map<std::vector<u64>, i64> map;
        for(int i = tree.size() - 1; i >= 2; i--) {
            int suffix_link = tree[i].suffix_link;
            map[tree[i].hash] = tree[i].num;
            tree[suffix_link].num += tree[i].num;
        }
        return map;
    }
private:
    std::string s;
    std::vector<Node> tree;
    int last_idx = 1;
    i64 sum = -1;
    rolling_hash<2> rh;
};

}

namespace ebi {

void main_() {
    rolling_hash<2>::set_base();
    std::string s,t;
    std::cin >> s >> t;
    palindromic_tree ptree_s(s), ptree_t(t);
    auto map_s = ptree_s.get_map();
    auto map_t = ptree_t.get_map();
    i64 ans = 0;
    for(auto [hash, cnt] : map_s) {
        ans += map_t[hash] * cnt;
    }
    std::cout << ans << '\n';
}

}  // namespace ebi

int main() {
    std::cout << std::fixed << std::setprecision(15);
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
    int t = 1;
    // std::cin >> t;
    while (t--) {
        ebi::main_();
    }
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 41020
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;

template<typename T = char>
struct MultiPalindromicTree{
private:
  struct Node{
    map<T, int> link;
    int link_rev = -1;
    int suffix_link; // same suffix maximum pal
    int len; // palindrome length
    vector<int> cnt; // freq of this
    pair<int, int> idx; // one of the start pos

    Node() = default;
    Node(int n, int len): len(len), cnt(n, 0), idx(-1, -1) {}

    int succ(const T &c) const {
      auto it = link.find(c);
      if(it == link.end()) return -1;
      return it->second;
    }
  };

  // find longest P s.t. c + P + c is pal
  int find_next_pal(int p, int k) const {
    int pos = int(seq[p].size()) - 1;
    while(true){
      int i = pos - 1 - nodes[k].len;
      if(i >= 0 && seq[p][i] == seq[p][pos]) return k;
      k = nodes[k].suffix_link;
    }
  }

public:

  int n;
  vector<Node> nodes;
  vector<vector<T>> seq;
  vector<vector<int>> ston;
  vector<int> suffix_max;


  MultiPalindromicTree(int n): n(n), seq(n), ston(n), suffix_max(n){
    nodes.emplace_back(n, -1); // odd node
    nodes.emplace_back(n, 0); // even node
    nodes[1].suffix_link = 0;
  }

  void add(int i, const T &c){
    seq[i].push_back(c);
    int k = find_next_pal(i, suffix_max[i]);

    // c + P + c is already exists
    if(int p = nodes[k].succ(c); p != -1){
      ++nodes[p].cnt[i];
      suffix_max[i] = p;
      ston[i].push_back(p);
      return;
    }

    // unique
    nodes[k].link[c] = suffix_max[i] = int(nodes.size());
    ston[i].push_back(suffix_max[i]);
    int len = nodes[k].len + 2;
    nodes.emplace_back(n, len);
    
    nodes.back().cnt[i] = 1;
    nodes.back().idx = {i, int(seq[i].size()) - len};
    nodes.back().link_rev = k;

    if(len == 1) nodes.back().suffix_link = 1;
    else nodes.back().suffix_link = 
      nodes[find_next_pal(i, nodes[k].suffix_link)].link[c];
  }

  template<class Iiter>
  void add(int i, Iiter first, Iiter last){
    for(; first != last; ++first) add(i, *first);
  }
  
  template<class Container>
  void add(int i, const Container &c){
    add(i, begin(c), end(c));
  }

  // idx of suffix palindromes of node k
  vector<int> suffix_palindromes(int k) const {
    vector<int> ret;
    for(; nodes[k].len > 0; k = nodes[k].suffix_link){
      ret.push_back(k);
    }
    return ret;
  }

  // idx of substring palindromes of node k
  vector<int> substr_palindroms(int k) const {
    vector<int> ret, seen(nodes.size());
    queue<int> qu;
    qu.push(k); seen[k] = 1;
    for(; !qu.empty(); qu.pop()){
      int v = qu.front();
      ret.push_back(v);
      for(int u : {nodes[v].suffix_link, nodes[v].link_rev}){
        if(!seen[u]) qu.push(u), seen[u] = 1;
      }
    }
    return ret;
  }

  // not count ""
  int count() const { return int(nodes.size()) - 2; }

  vector<vector<int>> palindromes_frequency() const {
    int m = int(nodes.size());
    vector<vector<int>> freq(m, vector<int>(n));
    for(int i = m - 1; i >= 1; --i){
      for(int j = 0; j < n; ++j){
        freq[i][j] += nodes[i].cnt[j];
        freq[nodes[i].suffix_link][j] += freq[i][j];
      }
    }
    return freq;
  }

  const Node &operator[](int k) const { return nodes[k]; }
};


int main() {
  MultiPalindromicTree mpt(2);
  string s, t; cin >> s >> t;
  mpt.add(0, s);
  mpt.add(1, t);

  auto freq = mpt.palindromes_frequency();
  int64_t ans = 0;

  for(int i = 0; i < mpt.count(); ++i){
    ans += freq[i + 2][0] * 1ll * freq[i + 2][1];
  }

  cout << ans << "\n";
}
accuracy: 1
time_ms: 10
memory_kb: 27892
final_rank: 8

code_snippet: #line 1 "zzz\\a.cpp"
#include <bits/stdc++.h>
using namespace std;

#line 2 "string\\RollingHash.cpp"

struct RollingHash{
  static constexpr uint64_t mod = (1ull << 61) - 1;
  static constexpr uint64_t mask(int k){ return (1ull << k) - 1; }
  static constexpr uint64_t add(uint64_t a, uint64_t b){
    return ((a+=b) >= mod) ? (a - mod) : a;
  }
  static constexpr uint64_t mul(uint64_t a, uint64_t b){
    uint64_t au = a >> 31, ad = a & mask(31);
    uint64_t bu = b >> 31, bd = b & mask(31);
    int64_t mid = ad*bu + au*bd;
    uint64_t mu = mid >> 30, md = mid & mask(30);
    return au*bu*2 + mu + (md << 31) + ad*bd;
  }
  static constexpr uint64_t cal_mod(uint64_t x){
    uint64_t res = (x >> 61) + (x & mask(61));
    return (res>=mod) ? (res-mod) : res;
  }

  static inline uint64_t generate_base(){
    mt19937_64 mt(random_device{}());
    uniform_int_distribution<uint64_t> rand(1, mod-1);
    return rand(mt);
  }

  inline void expand(size_t n){
    if(size_t pn = pow_table.size(); pn < n+1){
      pow_table.resize(n + 1);
      for(size_t i = pn-1; i < n; ++i){
        pow_table[i+1] = cal_mod(mul(pow_table[i], base));
      }
    }
  }

  const uint64_t base;
  vector<uint64_t> pow_table;

  RollingHash(uint64_t base = generate_base()): base(base), pow_table(1,1) {}

  vector<uint64_t> build(const string &s) const {
    int n = int(s.size());
    vector<uint64_t> res(n + 1);
    for(int i = 0; i < n; ++i) res[i+1] = cal_mod(mul(res[i], base) + s[i]);
    return res;
  }

  template<typename T>
  vector<uint64_t> build(const vector<T> &s) const {
    int n = int(s.size());
    vector<uint64_t> res(n + 1);
    for(int i = 0; i < n; ++i) res[i+1] = cal_mod(mul(res[i], base) + s[i]);
    return res;
  }

  uint64_t query(const vector<uint64_t> &s, int l = 0, size_t n = string::npos){
    n = min(n, s.size()-1 - l);
    expand(n);
    return cal_mod(s[l+n] + mod*4 - mul(s[l], pow_table[n]));
  }

  uint64_t cat(uint64_t hl, uint64_t hr, size_t hr_len){
    expand(hr_len);
    return cal_mod(mul(hl, pow_table[hr_len]) + hr);
  }

  int lcp(const vector<uint64_t> &a, int la, int ra, const vector<uint64_t> &b, int lb, int rb){
    int n = min(ra - la, rb - lb);
    int l = 0, r = n+1;
    while(r-l > 1){
      int m = (l+r) >> 1;
      if(query(a, la, m) == query(b, lb, m)) l = m;
      else r = m;
    }
    return l;
  }
};
#line 5 "zzz\\a.cpp"

template<typename T = char>
struct PalindromicTree{
private:
  struct Node{
    map<T, int> link;
    int suffix_link; // same suffix maximum pal
    int len; // palindrome length
    int cnt; // number of this
    int idx; // one of the start pos

    Node() = default;
    Node(int len, int cnt, int idx = -1): len(len), cnt(cnt), idx(idx) {}

    int succ(const T &c) const {
      auto it = link.find(c);
      if(it == link.end()) return -1;
      return it->second;
    }
  };

  // find longest P s.t. c + P + c is pal
  int find_next_pal(int k) const {
    int pos = int(seq.size()) - 1;
    while(true){
      int i = pos - 1 - nodes[k].len;
      if(i >= 0 && seq[i] == seq[pos]) return k;
      k = nodes[k].suffix_link;
    }
  }

public:

  vector<Node> nodes;
  vector<T> seq;
  vector<int> ston;
  int suffix_max;


  PalindromicTree(){
    nodes.emplace_back(-1, 0); // odd node
    nodes.emplace_back(0, 0); // even node
    nodes[1].suffix_link = 0;
    suffix_max = 0;
  }
  template<class Iiter>
  PalindromicTree(Iiter first, Iiter last): PalindromicTree() {
    add(first, last);
  }
  template<class Container>
  PalindromicTree(const Container &c): PalindromicTree() {
    add(c);
  }

  void add(const T &c){
    seq.push_back(c);
    int k = find_next_pal(suffix_max);

    // c + P + c is already exists
    if(int p = nodes[k].succ(c); p != -1){
      ++nodes[p].cnt;
      suffix_max = p;
      ston.push_back(p);
      return;
    }

    // unique
    nodes[k].link[c] = suffix_max = int(nodes.size());
    ston.push_back(suffix_max);
    int len = nodes[k].len + 2;
    nodes.emplace_back(len, 1, int(seq.size()) - len);

    if(len == 1) nodes.back().suffix_link = 1;
    else nodes.back().suffix_link = 
      nodes[find_next_pal(nodes[k].suffix_link)].link[c];
  }

  template<class Iiter>
  void add(Iiter first, Iiter last){
    for(; first != last; ++first) add(*first);
  }
  
  template<class Container>
  void add(const Container &c){
    add(begin(c), end(c));
  }

  // seq[i] = node[k].last
  int get_node_idx(int i) const { return ston[i]; }

  // length of suffix palindromes of node k
  vector<int> suffix_palindromes(int k) const {
    vector<int> ret;
    for(; nodes[k].len > 0; k = nodes[k].suffix_link){
      ret.push_back(nodes[k].len);
    }
    return ret;
  }

  // length of suffix palindromes of seq
  vector<int> suffix_palindromes() const {
    return suffix_palindromes(suffix_max);
  }

  // not count ""
  int count() const { return int(nodes.size()) - 2; }

  vector<int> palindromes_frequency() const {
    int n = int(nodes.size());
    vector<int> freq(n);
    for(int i = n - 1; i >= 1; --i){
      freq[i] += nodes[i].cnt;
      freq[nodes[i].suffix_link] += freq[i];
    }
    return freq;
  }
};

int main() {
  string s, t; cin >> s >> t;
  PalindromicTree ps(s), pt(t);
  map<uint64_t, int> mp;
  RollingHash rh;
  auto hs = rh.build(s);
  auto ht = rh.build(t);
  auto fs = ps.palindromes_frequency();
  auto ft = pt.palindromes_frequency();

  for(int i = 0; i < ps.count(); ++i){
    int p = ps.nodes[i + 2].idx;
    int l = ps.nodes[i + 2].len;
    int c = fs[i + 2];
    mp[rh.query(hs, p, l)] += c;
  }
  int64_t ans = 0;

  for(int i = 0; i < pt.count(); ++i){
    int p = pt.nodes[i + 2].idx;
    int l = pt.nodes[i + 2].len;
    int64_t c = ft[i + 2];
    ans += mp[rh.query(ht, p, l)] * c;
  }

  cout << ans << "\n";
}
accuracy: 1
time_ms: 30
memory_kb: 24020
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, x)    for(int i = 0; i < (x); i++)
#define rng(i, l, r) for(int i = (l); i < (r); i++)
using vi = vector<int>;
#define sz(x) (int)(x).size()

array<vi, 2> manacher(string &s) {
	int n = sz(s);
	array<vi, 2> p = {vi(n + 1), vi(n)};
	rep(z, 2) for(int i = 0, l = 0, r = 0; i < n; i++) {
		int t = r - i + !z;
		if(i < r) p[z][i] = min(t, p[z][l + t]);
		int L = i - p[z][i], R = i + p[z][i] - !z;
		while(L >= 1 and R + 1 < n and s[L - 1] == s[R + 1])
			p[z][i]++, L--, R++;
		if(R > r) l = L, r = R;
	}
	return p;
}


typedef uint64_t ull;
struct H {
	ull x;
	H(ull x = 0) : x(x) {}
	H operator+(H o) { return x + o.x + (x + o.x < x); }
	H operator-(H o) { return *this + ~o.x; }
	H operator*(H o) {
		auto m = (__uint128_t)x * o.x;
		return H((ull)m) + (ull)(m >> 64);
	}
	ull get() const { return x + !~x; }
	bool operator==(H o) const { return get() == o.get(); }
	bool operator<(H o) const { return get() < o.get(); }
};

static const H C = (ll)1e11 + 3;

struct hash_interval {
	vector<H> ha, pw;
	hash_interval(string &str) : ha(sz(str) + 1), pw(ha) {
		pw[0] = 1;
		rep(i, sz(str))
		    ha[i + 1] = ha[i] * C + str[i],
		           pw[i + 1] = pw[i] * C;
	}
	H get(int a, int b) { return ha[b] - ha[a] * pw[b - a]; }
};

map<ull, ll> palindromes_freq(string &s) {
	auto sm = manacher(s);
	hash_interval sh(s);
	set<ull> st;
	map<ull, ull> es;
	vector<set<ull>> nodes(sz(s) + 1);
	map<ull, ll> cum;
	rep(i, sz(s) + 1) {
		if(sm[0][i]) {
			int len = sm[0][i];
			auto ha = sh.get(i - len, i + len);
			cum[ha.get()]++;
			nodes[len * 2].insert(ha.get());
			while(len > 1) {
				len--;
				auto nx = sh.get(i - len, i + len);
				if(es.count({ha.get()})) break;
				es[ha.get()] = nx.get();
				ha = nx;
				nodes[len * 2].insert(ha.get());
			}
		}
	}

	rep(i, sz(s)) {
		sm[1][i]++;
		int len = sm[1][i];
		auto ha = sh.get(i - len + 1, i + len);
		cum[ha.get()]++;
		nodes[len * 2 - 1].insert(ha.get());
		while(len > 1) {
			len--;
			auto nx = sh.get(i - len + 1, i + len);
			if(es.count({ha.get()})) break;
			es[ha.get()] = nx.get();
			ha = nx;
			nodes[len * 2 - 1].insert(ha.get());
		}
	}

	for(int i = sz(s); i >= 0; --i) {
		for(auto &v : nodes[i]) {
			if(es.count(v)) {
				cum[es[v]] += cum[v];
			}
		}
	}
	return cum;
}

int main() {
	string s, t;
	cin >> s >> t;
	auto s_freq = palindromes_freq(s);
	auto t_freq = palindromes_freq(t);
	ll res = 0;
	for(auto [key, cnt] : s_freq) res += cnt * t_freq[key];
	cout << res << endl;
}
accuracy: 1
time_ms: 160
memory_kb: 18904
final_rank: 11

code_snippet: #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, x)    for(int i = 0; i < (x); i++)
#define rng(i, l, r) for(int i = (l); i < (r); i++)
using vi = vector<int>;
#define sz(x) (int)(x).size()

array<vi, 2> manacher(string &s) {
	int n = sz(s);
	array<vi, 2> p = {vi(n + 1), vi(n)};
	rep(z, 2) for(int i = 0, l = 0, r = 0; i < n; i++) {
		int t = r - i + !z;
		if(i < r) p[z][i] = min(t, p[z][l + t]);
		int L = i - p[z][i], R = i + p[z][i] - !z;
		while(L >= 1 and R + 1 < n and s[L - 1] == s[R + 1])
			p[z][i]++, L--, R++;
		if(R > r) l = L, r = R;
	}
	return p;
}


typedef uint64_t ull;
struct H {
	ull x;
	H(ull x = 0) : x(x) {}
	H operator+(H o) { return x + o.x + (x + o.x < x); }
	H operator-(H o) { return *this + ~o.x; }
	H operator*(H o) {
		auto m = (__uint128_t)x * o.x;
		return H((ull)m) + (ull)(m >> 64);
	}
	ull get() const { return x + !~x; }
	bool operator==(H o) const { return get() == o.get(); }
	bool operator<(H o) const { return get() < o.get(); }
};

static const H C = (ll)1e11 + 3;

struct hash_interval {
	vector<H> ha, pw;
	hash_interval(string &str) : ha(sz(str) + 1), pw(ha) {
		pw[0] = 1;
		rep(i, sz(str))
		    ha[i + 1] = ha[i] * C + str[i],
		           pw[i + 1] = pw[i] * C;
	}
	H get(int a, int b) { return ha[b] - ha[a] * pw[b - a]; }
};

map<ull, ll> palindromes_freq(string &s) {
	auto sm = manacher(s);
	hash_interval sh(s);
	set<ull> st;
	map<ull, ull> es;
	vector<set<ull>> nodes(sz(s) + 1);
	map<ull, ll> cum;
	rep(i, sz(s) + 1) {
		if(sm[0][i]) {
			int len = sm[0][i];
			auto ha = sh.get(i - len, i + len);
			cum[ha.get()]++;
			nodes[len * 2].insert(ha.get());
			while(len > 1) {
				len--;
				auto nx = sh.get(i - len, i + len);
				if(es.count({ha.get()})) break;
				es[ha.get()] = nx.get();
				ha = nx;
				nodes[len * 2].insert(ha.get());
			}
		}
	}

	rep(i, sz(s)) {
		sm[1][i]++;
		int len = sm[1][i];
		auto ha = sh.get(i - len + 1, i + len);
		cum[ha.get()]++;
		nodes[len * 2 - 1].insert(ha.get());
		while(len > 1) {
			len--;
			auto nx = sh.get(i - len + 1, i + len);
			if(es.count({ha.get()})) break;
			es[ha.get()] = nx.get();
			ha = nx;
			nodes[len * 2 - 1].insert(ha.get());
		}
	}

	for(int i = sz(s); i >= 0; --i) {
		for(auto &v : nodes[i]) {
			if(es.count(v)) {
				cum[es[v]] += cum[v];
			}
		}
	}
	return cum;
}

int main() {
	string s, t;
	cin >> s >> t;
	auto s_freq = palindromes_freq(s);
	auto t_freq = palindromes_freq(t);
	ll res = 0;
	for(auto [key, cnt] : s_freq) res += cnt * t_freq[key];
	cout << res << endl;
}
accuracy: 1
time_ms: 180
memory_kb: 20084
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod1=998244353,mod2=1000000007,MAX=300005,INF=1<<30;

// Manacher https://snuke.hatenablog.com/entry/2014/12/02/235837

vector<int> Manacher(string S){
    vector<int> R(si(S));
    int i = 0, j = 0;
    while (i < S.size()) {
        while (i-j >= 0 && i+j < S.size() && S[i-j] == S[i+j]) ++j;
        R[i] = j;
        int k = 1;
        while (i-k >= 0 && k+R[i-k] < j) R[i+k] = R[i-k], ++k;
        i += k; j -= k;
    }
    return R;
}
// 偶数長のも求めるために$を入れる必要がある

//ロリハ

struct Rollinghash{
    string S;
    int n;
    int base1;
    int base2;
    vector<ll> h1,h2,ru1,ru2;
    
    void make(string &T,int ba1,int ba2){
        S=T;
        n=S.size();
        h1.assign(n+1,0);
        h2.assign(n+1,0);
        ru1.assign(n+1,0);
        ru2.assign(n+1,0);
        base1=ba1;
        base2=ba2;
        
        ru1[0]=1;
        ru2[0]=1;
        
        for(int i=1;i<=n;i++){
            h1[i]=h1[i-1]*base1+ll(S[i-1]-'$'+1);
            h1[i]%=mod1;
            
            h2[i]=h2[i-1]*base2+ll(S[i-1]-'$'+1);
            h2[i]%=mod2;
            
            ru1[i]=ru1[i-1]*base1%mod1;
            ru2[i]=ru2[i-1]*base2%mod2;
        }
    }
    
    pair<ll,ll> ha(int l,int r){
        pair<ll,ll> res;
        res.fi=(h1[r]-h1[l]*ru1[r-l]%mod1+mod1)%mod1;
        res.se=(h2[r]-h2[l]*ru2[r-l]%mod2+mod2)%mod2;
        
        return res;
    }//開区間
};

//強連結成分分解

int V,cmp[MAX];
vector<int> G[MAX],rG[MAX],vs;//vsがトポソの逆順になってる
bool used[MAX];

int get_id(int i,bool f){
    return 2*i+f;
}

void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}

void either(int i,bool f,int j,bool g){
    add_edge(get_id(i,!f),get_id(j,g));
    add_edge(get_id(j,!g),get_id(i,f));
    //add_edge(2*i+(!f),2*j+g);
    //add_edge(2*j+(!g),2*i+f);
}

void imply(int i,bool f,int j,bool g){
    either(i,!f,j,g);
}
//iがfならばjがg

void must(int i,bool f){
    either(i,f,i,f);
}

void DFS(int v){
    used[v]=1;
    for(int i=0;i<G[v].size();i++){
        if(used[G[v][i]]==0) DFS(G[v][i]);
    }
    vs.push_back(v);
}

void rDFS(int v,int k){
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++){
        if(used[rG[v][i]]==0) rDFS(rG[v][i],k);
    }
}

int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(used[v]==0) DFS(v);
    }
    
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(used[vs[i]]==0) rDFS(vs[i],k++);
    }
    return k;
}

ll dp[MAX];

void init(int sz){
    V=sz;
    for(int i=0;i<V;i++){
        dp[i]=0;
        cmp[i]=0;
        G[i].clear();
        rG[i].clear();
        used[i]=false;
    }
    vs.clear();
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    string S,T;cin>>S>>T;
    string SS,TT;
    SS+='$';TT+='$';
    for(char c:S){
        SS+=c;
        SS+='$';
    }
    for(char c:T){
        TT+=c;
        TT+='$';
    }
    S=SS;
    T=TT;
    
    ll ha1=103,ha2=109;
    
    map<pair<ll,ll>,ll> MA1,MA2;
    
    for(int q=0;q<2;q++){
        map<pair<ll,ll>,ll> dic;
        Rollinghash ro;
        ro.make(S,ha1,ha2);
        init(MAX);
        
        auto mana=Manacher(S);
        
        for(int i=0;i<si(S);i++){
            int s=(i-mana[i]+1);
            if(s%2==0) s++;
            pair<ll,ll> la=mp(-1,-1);
            for(int l=s;l<=i;l+=2){
                int r=i+(i-l)+1;
                auto re=ro.ha(l,r);
                if(dic.count(re)){
                    if(l==s) dp[dic[re]]++;
                    else{
                        add_edge(dic[la],dic[re]);
                    }
                    break;
                }else{
                    int sz=si(dic);
                    dic[re]=sz;
                    if(l==s) dp[sz]++;
                    else{
                        add_edge(dic[la],dic[re]);
                    }
                    la=re;
                }
            }
        }
        
        V=si(dic);
        
        scc();
        
        reverse(all(vs));
        
        for(int a:vs){
            for(int to:G[a]){
                dp[to]+=dp[a];
            }
        }
        
        for(auto a:dic){
            MA1[a.fi]+=dp[a.se];
        }
        
        swap(S,T);
        swap(MA1,MA2);
    }
    
    ll ans=0;
    
    for(auto a:MA1){
        if(MA2.count(a.fi)) ans+=a.se*MA2[a.fi];
    }
    
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 110
memory_kb: 38324
final_rank: 15

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < int(n); ++i)
#define repp(i,n,m) for (int i = m; i < int(n); ++i)
#define repb(i,n) for (int i = int(n)-1; i >= 0; --i)
#define all(v) v.begin(),v.end()
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<int, int>;
using PL = pair<long long, long long>;
using pdd = pair<long double, long double>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;
using ppi = pair<P,int>;
using pip = pair<int,P>;
const int INF = 1001001007;
const long long mod1 = 1000000007LL;
const long long mod2 = 998244353LL;
const ll inf = 2e18;
const ld pi = 3.14159265358979323;
const ld eps = 1e-7;
template<typename T>void o(T a);
template<class T>istream &operator>>(istream &is,vector<T> &v){for(auto &e:v)is>>e;return is;}
template<class T>istream &operator>>(istream &is,vector<vector<T>> &v){for(auto &e:v)is>>e;return is;}
template<typename T>bool range(T a,T b,T x){return (a<=x&&x<b);}
template<typename T>bool rrange(T a,T b,T c,T d,T x,T y){return (range(a,c,x)&&range(b,d,y));}
template<typename T>void rev(vector<T> &v){reverse(v.begin(),v.end());}
void revs(string &s) {reverse(s.begin(),s.end());}
template<typename T>void sor(vector<T> &v, int f=0){sort(v.begin(),v.end());if(f!=0) rev(v);}
template<typename T>bool chmin(T &a,const T &b){if(a>b){a=b;return true;}return false;}
template<typename T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<typename T>void uniq(vector<T> &v){sor(v);v.erase(unique(v.begin(),v.end()),v.end());}
template<typename T>T cel(T a,T b){return (a+b-1)/b;}
template<typename T1, typename T2>void print(pair<T1,T2> a);
template<typename T>void print(vector<T> v);
template<typename T>void print(vector<vector<T>> v);
void print(){ putchar(' '); }
void print(bool a){ printf("%d", a); }
void print(int a){ printf("%d", a); }
void print(long a){ printf("%ld", a); }
void print(long long a){ printf("%lld", a); }
void print(char a){ printf("%c", a); }
void print(char a[]){ printf("%s", a); }
void print(const char a[]){ printf("%s", a); }
void print(long double a){ printf("%.15Lf", a); }
void print(const string& a){ for(auto&& i : a) print(i); }
template<class T> void print(const T& a){ cout << a; }
int out(){ putchar('\n'); return 0; }
template<class T> int out(const T& t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }
void o(){cout<<"!?"<<endl;}
template<typename T>void o(T a){cout<<a<<endl;}
template<typename T1,typename T2>void print(pair<T1,T2> a){print(a.first);print(),print(a.second);}
template<typename T>void print(vector<T> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())print();}}
template<typename T>void print(vector<vector<T>> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())out();}}
void yes(){out("Yes");}
void no (){out("No");}
void yn (bool t){if(t)yes();else no();}
template<typename T>void dame(bool t, T s){if(!t){out(s);exit(0);}}
vector<int> dx = {0,1,0,-1,1,1,-1,-1};
vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll mpow(ll x,ll n,ll m){if(n==0)return 1LL;x%=m;ll a=mpow(x,n/2,m);a=a*a%m;return (n&1)?a*x%m:a;}


vector<int> manacher(string &s){
    int n = s.size();
    vector<int> ans(n,0);
    int i = 0, len = 0;
    while (i < n){
        while (i - len >= 0 && i + len < n && s[i-len] == s[i+len]) len++;
        ans[i] = len;
        int k = 1;
        while (i - k >= 0 && k + ans[i-k] < len) ans[i+k] = ans[i-k], k++;
        i += k, len -= k;
    }
    return ans;
}

vector<int> palindrome_length(string s){
    string t = "$";
    for (char c : s) t += c, t += '$';
    vector<int> a = manacher(t);
    vector<int> ans(a.size()-2);
    rep(i,a.size()-2) ans[i] = a[i+1]-1;
    return ans;
}

#include<random>
struct RollingHash {
    using ull = unsigned long long;
    RollingHash(const string &s = ""){ build(s);}
    ull get(int l, int r){ return cal_mod(inner_hush[r] + POSITIVISER - mul_mod(inner_hush[l], pow_base[r-l]));}
  private:
    static constexpr ull MASK30 = (1UL << 30) - 1;
    static constexpr ull MASK31 = (1UL << 31) - 1;
    static constexpr ull MASK61 = (1UL << 61) - 1;
    static constexpr ull MOD = (1UL << 61) - 1;
    static constexpr ull POSITIVISER = MOD * 4;
    string str;
    int n;
    static ull BASE;
    static vector<ull> pow_base;
    static ull mul_mod(ull a, ull b){
        ull au = a >> 31, ad = a & MASK31;
        ull bu = b >> 31, bd = b & MASK31;
        ull mid = ad * bu + au * bd;
        ull midu = mid >> 30, midd = mid & MASK30;
        return (au * bu * 2 + midu + (midd << 31) + ad * bd);
    }
    static ull cal_mod(ull x){
        ull xu = x >> 61;
        ull xd = x & MASK61;
        ull res = xu + xd;
        if (res >= MOD) res -= MOD;
        return res;
    }
    vector<ull> inner_hush;
    void build(const string &s){
        if (BASE == 0) BASE = (1UL<<31) + (random_device()() & MASK31);
        str = s;
        n = s.size();
        int nlen = pow_base.size();
        if (nlen < n+1){
            pow_base.resize(n+1);
            for (int i = nlen; i <= n; i++){
                pow_base[i] = cal_mod(mul_mod(pow_base[i-1],BASE));
            }
        }
        inner_hush.resize(n+1);
        inner_hush[0] = 0;
        for (int i = 0; i < n; i++) inner_hush[i+1] = cal_mod(mul_mod(inner_hush[i],BASE) + s[i]);
    }
};
using ull = unsigned long long;
ull RollingHash::BASE = 0;
vector<ull> RollingHash::pow_base = vector<ull>(1,1);
using roriha = RollingHash;

void solve(){
    string s, t; cin >> s >> t;
    int n = s.size(), m = t.size();
    auto nma = palindrome_length(s);
    auto mma = palindrome_length(t);
    roriha a(s), b(t);
    map<ull,ll> nmp, mmp;
    priority_queue<pip> pque;
    rep(i,nma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (nma[i]-1)/2;
            int ri = ce + (nma[i]-1)/2; 
            ull hs = a.get(le,ri+1);
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1;
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
        else {
            if (nma[i] == 0) continue;
            int le = (i - 1 - (nma[i] / 2 - 1) * 2) / 2;
            int ri = (i + 1 + (nma[i] / 2 - 1) * 2) / 2;
            ull hs = a.get(le,ri+1);
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1;
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        ull ihs = a.get(le,ri+1);
        le++, ri--;
        ull hs = a.get(le,ri+1);
        if (nmp.find(hs) == nmp.end()){
            nmp[hs] = nmp[ihs];
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else nmp[hs] += nmp[ihs];
    }
    rep(i,mma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (mma[i]-1)/2;
            int ri = ce + (mma[i]-1)/2;
            ull hs = b.get(le,ri+1);
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1;
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
        else {
            if (mma[i] == 0) continue;
            int le = (i - 1 - (mma[i] / 2 - 1) * 2) / 2;
            int ri = (i + 1 + (mma[i] / 2 - 1) * 2) / 2;
            ull hs = b.get(le,ri+1);
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1;
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        ull ihs = b.get(le,ri+1);
        le++, ri--;
        ull hs = b.get(le,ri+1);
        if (mmp.find(hs) == mmp.end()){
            mmp[hs] = mmp[ihs];
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else mmp[hs] += mmp[ihs];
    }
    ll ans = 0;
    for (auto p : nmp){
        if (mmp.find(p.first) == mmp.end()) continue;
        ans += p.second * mmp[p.first];
    }
    out(ans);
}

int main(){
    int t = 1; //cin >> t;
    while (t--) solve();
}
accuracy: 1
time_ms: 80
memory_kb: 12176
final_rank: 3

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < int(n); ++i)
#define repp(i,n,m) for (int i = m; i < int(n); ++i)
#define repb(i,n) for (int i = int(n)-1; i >= 0; --i)
#define all(v) v.begin(),v.end()
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<int, int>;
using PL = pair<long long, long long>;
using pdd = pair<long double, long double>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;
using ppi = pair<P,int>;
using pip = pair<int,P>;
const int INF = 1001001007;
const long long mod1 = 1000000007LL;
const long long mod2 = 998244353LL;
const ll inf = 2e18;
const ld pi = 3.14159265358979323;
const ld eps = 1e-7;
template<typename T>void o(T a);
template<class T>istream &operator>>(istream &is,vector<T> &v){for(auto &e:v)is>>e;return is;}
template<class T>istream &operator>>(istream &is,vector<vector<T>> &v){for(auto &e:v)is>>e;return is;}
template<typename T>bool range(T a,T b,T x){return (a<=x&&x<b);}
template<typename T>bool rrange(T a,T b,T c,T d,T x,T y){return (range(a,c,x)&&range(b,d,y));}
template<typename T>void rev(vector<T> &v){reverse(v.begin(),v.end());}
void revs(string &s) {reverse(s.begin(),s.end());}
template<typename T>void sor(vector<T> &v, int f=0){sort(v.begin(),v.end());if(f!=0) rev(v);}
template<typename T>bool chmin(T &a,const T &b){if(a>b){a=b;return true;}return false;}
template<typename T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<typename T>void uniq(vector<T> &v){sor(v);v.erase(unique(v.begin(),v.end()),v.end());}
template<typename T>T cel(T a,T b){return (a+b-1)/b;}
template<typename T1, typename T2>void print(pair<T1,T2> a);
template<typename T>void print(vector<T> v);
template<typename T>void print(vector<vector<T>> v);
void print(){ putchar(' '); }
void print(bool a){ printf("%d", a); }
void print(int a){ printf("%d", a); }
void print(long a){ printf("%ld", a); }
void print(long long a){ printf("%lld", a); }
void print(char a){ printf("%c", a); }
void print(char a[]){ printf("%s", a); }
void print(const char a[]){ printf("%s", a); }
void print(long double a){ printf("%.15Lf", a); }
void print(const string& a){ for(auto&& i : a) print(i); }
template<class T> void print(const T& a){ cout << a; }
int out(){ putchar('\n'); return 0; }
template<class T> int out(const T& t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }
void o(){cout<<"!?"<<endl;}
template<typename T>void o(T a){cout<<a<<endl;}
template<typename T1,typename T2>void print(pair<T1,T2> a){print(a.first);print(),print(a.second);}
template<typename T>void print(vector<T> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())print();}}
template<typename T>void print(vector<vector<T>> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())out();}}
void yes(){out("Yes");}
void no (){out("No");}
void yn (bool t){if(t)yes();else no();}
template<typename T>void dame(bool t, T s){if(!t){out(s);exit(0);}}
vector<int> dx = {0,1,0,-1,1,1,-1,-1};
vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll mpow(ll x,ll n,ll m){if(n==0)return 1LL;x%=m;ll a=mpow(x,n/2,m);a=a*a%m;return (n&1)?a*x%m:a;}


vector<int> manacher(string &s){
    int n = s.size();
    vector<int> ans(n,0);
    int i = 0, len = 0;
    while (i < n){
        while (i - len >= 0 && i + len < n && s[i-len] == s[i+len]) len++;
        ans[i] = len;
        int k = 1;
        while (i - k >= 0 && k + ans[i-k] < len) ans[i+k] = ans[i-k], k++;
        i += k, len -= k;
    }
    return ans;
}

vector<int> palindrome_length(string s){
    string t = "$";
    for (char c : s) t += c, t += '$';
    vector<int> a = manacher(t);
    vector<int> ans(a.size()-2);
    rep(i,a.size()-2) ans[i] = a[i+1]-1;
    return ans;
}
//using ulong = unsigned long long;
const ulong MASK30 = (1UL << 30) - 1;
const ulong MASK31 = (1UL << 31) - 1;
const ulong MOD = (1UL << 61) - 1;
const ulong MASK61 = MOD;
ulong CalcMod(ulong x);

//a*b mod 2^61-1を返す関数(最後にModを取る)
ulong Mul(ulong a, ulong b)
{
    ulong au = a >> 31;
    ulong ad = a & MASK31;
    ulong bu = b >> 31;
    ulong bd = b & MASK31;
    ulong mid = ad * bu + au * bd;
    ulong midu = mid >> 30;
    ulong midd = mid & MASK30;
    return (au * bu * 2 + midu + (midd << 31) + ad * bd);
}

//mod 2^61-1を計算する関数
ulong CalcMod(ulong x)
{
    ulong xu = x >> 61;
    ulong xd = x & MASK61;
    ulong res = xu + xd;
    if (res >= MOD) res -= MOD;
    return res;
}

const ulong Base = 294576;
vector<ulong> bs;

void solve(){
    string s, t; cin >> s >> t;
    int n = s.size(), m = t.size();
    //bs.resize(100000,1);
    //rep(i,100000-1) bs[i+1] = Mul(bs[i],base);
    //vector<ulong> nrui(n+1,0), mrui(m+1,0);
    vector<ulong> powMemo(100000,1);
    rep(i,100000-1) powMemo[i+1] = CalcMod(Mul(powMemo[i],Base));
    vector<ulong> hash1(n+1,0); //要素数n+1の配列を初期化
    for (int i = 0; i < n; i++) hash1[i + 1] = CalcMod(Mul(hash1[i], Base) + s[i]);
    vector<ulong> hash2(m+1,0); //要素数n+1の配列を初期化
    for (int i = 0; i < m; i++) hash2[i + 1] = CalcMod(Mul(hash2[i], Base) + t[i]);
    //rep(i,n) nrui[i+1] = CalcMod(nrui[i] + Mul(ulong(s[i] - 'a' + 1), bs[i]));
    //rep(i,m) mrui[i+1] = CalcMod(mrui[i] + Mul(ulong(t[i] - 'a' + 1), bs[i]));
    const ulong POSITIVIZER = MOD * 4;
    auto nget = [&](int l, int r){
        //return Mul(CalcMod(nrui[r] - nrui[l] + MOD),bs[100000-1-r]);
        return CalcMod(hash1[r] + POSITIVIZER - Mul(hash1[l], powMemo[r - l]));
    };
    auto mget = [&](int l, int r){
        //return Mul(CalcMod(nrui[r] - nrui[l] + MOD),bs[100000-1-r]);
        return CalcMod(hash2[r] + POSITIVIZER - Mul(hash2[l], powMemo[r - l]));
    };
    auto nma = palindrome_length(s);
    auto mma = palindrome_length(t);
    map<ulong,ll> nmp, mmp;
    priority_queue<pip> pque;
    rep(i,nma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (nma[i]-1)/2;
            int ri = ce + (nma[i]-1)/2; 
            ulong hs = nget(le,ri+1);
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1; //out(le,ri,hs);
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
        else {
            if (nma[i] == 0) continue;
            int le = (i - 1 - (nma[i] / 2 - 1) * 2) / 2;
            int ri = (i + 1 + (nma[i] / 2 - 1) * 2) / 2;
            ulong hs = nget(le,ri+1);
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1;
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        ulong ihs = nget(le,ri+1);
        le++, ri--;
        ulong hs = nget(le,ri+1);
        if (nmp.find(hs) == nmp.end()){
            nmp[hs] = nmp[ihs]; //out(le,ri,hs);
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else nmp[hs] += nmp[ihs];
    }
    rep(i,mma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (mma[i]-1)/2;
            int ri = ce + (mma[i]-1)/2;
            ulong hs = mget(le,ri+1);
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1; //out(le,ri,hs);
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
        else {
            if (mma[i] == 0) continue;
            int le = (i - 1 - (mma[i] / 2 - 1) * 2) / 2;
            int ri = (i + 1 + (mma[i] / 2 - 1) * 2) / 2;
            ulong hs = mget(le,ri+1);
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1;
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        ulong ihs = mget(le,ri+1);
        le++, ri--;
        ulong hs = mget(le,ri+1);
        if (mmp.find(hs) == mmp.end()){
            mmp[hs] = mmp[ihs];//out(le,ri,hs);
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else mmp[hs] += mmp[ihs];
    }
    ll ans = 0;
    for (auto p : nmp){ //out(p.first,p.second);
        if (mmp.find(p.first) == mmp.end()) continue;
        ans += p.second * mmp[p.first]; //out(p.second,mmp[p.first]);
    }
    for (auto q : mmp){
        //out(q.first, q.second);
    }
    out(ans);
}

int main(){
    int t = 1; //cin >> t;
    while (t--) solve();
}
accuracy: 1
time_ms: 80
memory_kb: 12320
final_rank: 4

code_snippet: #line 1 "aoj.cpp"
#include<bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < int(n); ++i)
#define repp(i,n,m) for (int i = m; i < int(n); ++i)
#define repb(i,n) for (int i = int(n)-1; i >= 0; --i)
#define all(v) v.begin(),v.end()
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<int, int>;
using PL = pair<long long, long long>;
using pdd = pair<long double, long double>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;
using ppi = pair<P,int>;
using pip = pair<int,P>;
const int INF = 1001001007;
const long long mod1 = 1000000007LL;
const long long mod2 = 998244353LL;
const ll inf = 2e18;
const ld pi = 3.14159265358979323;
const ld eps = 1e-7;
template<typename T>void o(T a);
template<class T>istream &operator>>(istream &is,vector<T> &v){for(auto &e:v)is>>e;return is;}
template<class T>istream &operator>>(istream &is,vector<vector<T>> &v){for(auto &e:v)is>>e;return is;}
template<typename T>bool range(T a,T b,T x){return (a<=x&&x<b);}
template<typename T>bool rrange(T a,T b,T c,T d,T x,T y){return (range(a,c,x)&&range(b,d,y));}
template<typename T>void rev(vector<T> &v){reverse(v.begin(),v.end());}
void revs(string &s) {reverse(s.begin(),s.end());}
template<typename T>void sor(vector<T> &v, int f=0){sort(v.begin(),v.end());if(f!=0) rev(v);}
template<typename T>bool chmin(T &a,const T &b){if(a>b){a=b;return true;}return false;}
template<typename T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<typename T>void uniq(vector<T> &v){sor(v);v.erase(unique(v.begin(),v.end()),v.end());}
template<typename T>T cel(T a,T b){return (a+b-1)/b;}
template<typename T1, typename T2>void print(pair<T1,T2> a);
template<typename T>void print(vector<T> v);
template<typename T>void print(vector<vector<T>> v);
void print(){ putchar(' '); }
void print(bool a){ printf("%d", a); }
void print(int a){ printf("%d", a); }
void print(long a){ printf("%ld", a); }
void print(long long a){ printf("%lld", a); }
void print(char a){ printf("%c", a); }
void print(char a[]){ printf("%s", a); }
void print(const char a[]){ printf("%s", a); }
void print(long double a){ printf("%.15Lf", a); }
void print(const string& a){ for(auto&& i : a) print(i); }
template<class T> void print(const T& a){ cout << a; }
int out(){ putchar('\n'); return 0; }
template<class T> int out(const T& t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }
void o(){cout<<"!?"<<endl;}
template<typename T>void o(T a){cout<<a<<endl;}
template<typename T1,typename T2>void print(pair<T1,T2> a){print(a.first);print(),print(a.second);}
template<typename T>void print(vector<T> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())print();}}
template<typename T>void print(vector<vector<T>> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())out();}}
void yes(){out("Yes");}
void no (){out("No");}
void yn (bool t){if(t)yes();else no();}
template<typename T>void dame(bool t, T s){if(!t){out(s);exit(0);}}
vector<int> dx = {0,1,0,-1,1,1,-1,-1};
vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll mpow(ll x,ll n,ll m){if(n==0)return 1LL;x%=m;ll a=mpow(x,n/2,m);a=a*a%m;return (n&1)?a*x%m:a;}


vector<int> manacher(string &s){
    int n = s.size();
    vector<int> ans(n,0);
    int i = 0, len = 0;
    while (i < n){
        while (i - len >= 0 && i + len < n && s[i-len] == s[i+len]) len++;
        ans[i] = len;
        int k = 1;
        while (i - k >= 0 && k + ans[i-k] < len) ans[i+k] = ans[i-k], k++;
        i += k, len -= k;
    }
    return ans;
}

vector<int> palindrome_length(string s){
    string t = "$";
    for (char c : s) t += c, t += '$';
    vector<int> a = manacher(t);
    vector<int> ans(a.size()-2);
    rep(i,a.size()-2) ans[i] = a[i+1]-1;
    return ans;
}

#line 2 "modint.hpp"
// for prime m
template <long long m>
struct static_modint {
    using mint = static_modint;
    
  public:
    static constexpr int mod() { return m; }
    static_modint() : _v(0) {}
    template <class T>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        assert(_v);
        return pow(umod() - 2);
    }

    mint inverse() const {return inv();}

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }
    friend std::ostream &operator<<(std::ostream &os,const mint&p) {
        return os<<p.val();
    }
    friend std::istream &operator>>(std::istream &is, mint &a) {
        long long t;
        is>>t;
        a=mint(t);
        return (is);
    }
    
  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
};

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
#line 95 "aoj.cpp"
using mint = modint998244353;
const mint base = 249134723;
vector<mint> bs;
vector<mint> ibs;

void solve(){
    string s, t; cin >> s >> t;
    int n = s.size(), m = t.size();
    bs.resize(100000,1), ibs.resize(100000,1);
    rep(i,100000-1) bs[i+1] = bs[i] * base;
    ibs[100000-1] = bs[100000-1].inv();
    repb(i,100000-1) ibs[i] = ibs[i+1] * base;
    vector<mint> nrui(n+1,0), mrui(m+1,0);
    rep(i,n) nrui[i+1] = nrui[i] + mint(ll(s[i] - 'a' + 1)) * bs[i];
    rep(i,m) mrui[i+1] = mrui[i] + mint(ll(t[i] - 'a' + 1)) * bs[i];
    auto nget = [&](int l, int r){
        return (nrui[r] - nrui[l]) * ibs[l];
    };
    auto mget = [&](int l, int r){
        return (mrui[r] - mrui[l]) * ibs[l];
    };
    auto nma = palindrome_length(s);
    auto mma = palindrome_length(t);
    map<ll,ll> nmp, mmp;
    priority_queue<pip> pque;
    rep(i,nma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (nma[i]-1)/2;
            int ri = ce + (nma[i]-1)/2; 
            mint mhs = nget(le,ri+1);
            ll hs = mhs.val();
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1; //out(le,ri,hs);
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
        else {
            if (nma[i] == 0) continue;
            int le = (i - 1 - (nma[i] / 2 - 1) * 2) / 2;
            int ri = (i + 1 + (nma[i] / 2 - 1) * 2) / 2;
            mint mhs = nget(le,ri+1);
            ll hs = mhs.val();
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1;
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        mint imhs = nget(le,ri+1);
        ll ihs = imhs.val();
        le++, ri--;
        mint mhs = nget(le,ri+1);
        ll hs = mhs.val();
        if (nmp.find(hs) == nmp.end()){
            nmp[hs] = nmp[ihs]; //out(le,ri,hs);
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else nmp[hs] += nmp[ihs];
    }
    rep(i,mma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (mma[i]-1)/2;
            int ri = ce + (mma[i]-1)/2;
            mint mhs = mget(le,ri+1);
            ll hs = mhs.val();
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1; //out(le,ri,hs);
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
        else {
            if (mma[i] == 0) continue;
            int le = (i - 1 - (mma[i] / 2 - 1) * 2) / 2;
            int ri = (i + 1 + (mma[i] / 2 - 1) * 2) / 2;
            mint mhs = mget(le,ri+1);
            ll hs = mhs.val();
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1;
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        mint imhs = mget(le,ri+1);
        ll ihs = imhs.val();
        le++, ri--;
        mint mhs = mget(le,ri+1);
        ll hs = mhs.val();
        if (mmp.find(hs) == mmp.end()){
            mmp[hs] = mmp[ihs];//out(le,ri,hs);
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else mmp[hs] += mmp[ihs];
    }
    ll ans = 0;
    for (auto p : nmp){ //out(p.first,p.second);
        if (mmp.find(p.first) == mmp.end()) continue;
        ans += p.second * mmp[p.first]; //out(p.second,mmp[p.first]);
    }
    for (auto q : mmp){
        //out(q.first, q.second);
    }
    out(ans);
}

int main(){
    int t = 1; //cin >> t;
    while (t--) solve();
}
accuracy: 0.15
time_ms: 80
memory_kb: 11872
final_rank: 17

code_snippet: #line 1 "aoj.cpp"
#include<bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < int(n); ++i)
#define repp(i,n,m) for (int i = m; i < int(n); ++i)
#define repb(i,n) for (int i = int(n)-1; i >= 0; --i)
#define all(v) v.begin(),v.end()
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<int, int>;
using PL = pair<long long, long long>;
using pdd = pair<long double, long double>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;
using ppi = pair<P,int>;
using pip = pair<int,P>;
const int INF = 1001001007;
const long long mod1 = 1000000007LL;
const long long mod2 = 998244353LL;
const ll inf = 2e18;
const ld pi = 3.14159265358979323;
const ld eps = 1e-7;
template<typename T>void o(T a);
template<class T>istream &operator>>(istream &is,vector<T> &v){for(auto &e:v)is>>e;return is;}
template<class T>istream &operator>>(istream &is,vector<vector<T>> &v){for(auto &e:v)is>>e;return is;}
template<typename T>bool range(T a,T b,T x){return (a<=x&&x<b);}
template<typename T>bool rrange(T a,T b,T c,T d,T x,T y){return (range(a,c,x)&&range(b,d,y));}
template<typename T>void rev(vector<T> &v){reverse(v.begin(),v.end());}
void revs(string &s) {reverse(s.begin(),s.end());}
template<typename T>void sor(vector<T> &v, int f=0){sort(v.begin(),v.end());if(f!=0) rev(v);}
template<typename T>bool chmin(T &a,const T &b){if(a>b){a=b;return true;}return false;}
template<typename T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<typename T>void uniq(vector<T> &v){sor(v);v.erase(unique(v.begin(),v.end()),v.end());}
template<typename T>T cel(T a,T b){return (a+b-1)/b;}
template<typename T1, typename T2>void print(pair<T1,T2> a);
template<typename T>void print(vector<T> v);
template<typename T>void print(vector<vector<T>> v);
void print(){ putchar(' '); }
void print(bool a){ printf("%d", a); }
void print(int a){ printf("%d", a); }
void print(long a){ printf("%ld", a); }
void print(long long a){ printf("%lld", a); }
void print(char a){ printf("%c", a); }
void print(char a[]){ printf("%s", a); }
void print(const char a[]){ printf("%s", a); }
void print(long double a){ printf("%.15Lf", a); }
void print(const string& a){ for(auto&& i : a) print(i); }
template<class T> void print(const T& a){ cout << a; }
int out(){ putchar('\n'); return 0; }
template<class T> int out(const T& t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }
void o(){cout<<"!?"<<endl;}
template<typename T>void o(T a){cout<<a<<endl;}
template<typename T1,typename T2>void print(pair<T1,T2> a){print(a.first);print(),print(a.second);}
template<typename T>void print(vector<T> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())print();}}
template<typename T>void print(vector<vector<T>> v){for(auto ite=v.begin();ite!=v.end();){print(*ite);if(++ite!=v.end())out();}}
void yes(){out("Yes");}
void no (){out("No");}
void yn (bool t){if(t)yes();else no();}
template<typename T>void dame(bool t, T s){if(!t){out(s);exit(0);}}
vector<int> dx = {0,1,0,-1,1,1,-1,-1};
vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll mpow(ll x,ll n,ll m){if(n==0)return 1LL;x%=m;ll a=mpow(x,n/2,m);a=a*a%m;return (n&1)?a*x%m:a;}


vector<int> manacher(string &s){
    int n = s.size();
    vector<int> ans(n,0);
    int i = 0, len = 0;
    while (i < n){
        while (i - len >= 0 && i + len < n && s[i-len] == s[i+len]) len++;
        ans[i] = len;
        int k = 1;
        while (i - k >= 0 && k + ans[i-k] < len) ans[i+k] = ans[i-k], k++;
        i += k, len -= k;
    }
    return ans;
}

vector<int> palindrome_length(string s){
    string t = "$";
    for (char c : s) t += c, t += '$';
    vector<int> a = manacher(t);
    vector<int> ans(a.size()-2);
    rep(i,a.size()-2) ans[i] = a[i+1]-1;
    return ans;
}

#line 2 "modint.hpp"
// for prime m
template <long long m>
struct static_modint {
    using mint = static_modint;
    
  public:
    static constexpr int mod() { return m; }
    static_modint() : _v(0) {}
    template <class T>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        assert(_v);
        return pow(umod() - 2);
    }

    mint inverse() const {return inv();}

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }
    friend std::ostream &operator<<(std::ostream &os,const mint&p) {
        return os<<p.val();
    }
    friend std::istream &operator>>(std::istream &is, mint &a) {
        long long t;
        is>>t;
        a=mint(t);
        return (is);
    }
    
  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
};

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
#line 95 "aoj.cpp"
using mint = modint998244353;
const mint base = 249134723;
vector<mint> bs;
vector<mint> ibs;

void solve(){
    string s, t; cin >> s >> t;
    int n = s.size(), m = t.size();
    bs.resize(100000,1), ibs.resize(100000,1);
    rep(i,100000-1) bs[i+1] = bs[i] * base;
    ibs[100000-1] = bs[100000-1].inv();
    repb(i,100000-1) ibs[i] = ibs[i+1] * base;
    vector<mint> nrui(n+1,0), mrui(m+1,0);
    rep(i,n) nrui[i+1] = nrui[i] + mint(ll(s[i] - 'a' + 1)) * bs[i];
    rep(i,m) mrui[i+1] = mrui[i] + mint(ll(t[i] - 'a' + 1)) * bs[i];
    auto nget = [&](int l, int r){
        return (nrui[r] - nrui[l]) * ibs[l];
    };
    auto mget = [&](int l, int r){
        return (mrui[r] - mrui[l]) * ibs[l];
    };
    auto nma = palindrome_length(s);
    auto mma = palindrome_length(t);
    map<ll,ll> nmp, mmp;
    priority_queue<pip> pque;
    rep(i,nma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (nma[i]-1)/2;
            int ri = ce + (nma[i]-1)/2; 
            mint mhs = nget(le,ri+1);
            ll hs = mhs.val();
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1; //out(le,ri,hs);
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
        else {
            int le = (i - (nma[i])) / 2;
            int ri = (i + (nma[i])) / 2;
            if (le == ri) continue;
            mint mhs = nget(le,ri+1);
            ll hs = mhs.val();
            if (nmp.find(hs) == nmp.end()){
                nmp[hs] = 1;
                pque.push(pip(nma[i],P(le,ri)));
            }
            else nmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        mint imhs = nget(le,ri+1);
        ll ihs = imhs.val();
        le++, ri--;
        mint mhs = nget(le,ri+1);
        ll hs = mhs.val();
        if (nmp.find(hs) == nmp.end()){
            nmp[hs] = nmp[ihs]; //out(le,ri,hs);
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else nmp[hs] += nmp[ihs];
    }
    rep(i,mma.size()){
        if (i % 2 == 0){
            int ce = i / 2;
            int le = ce - (mma[i]-1)/2;
            int ri = ce + (mma[i]-1)/2;
            mint mhs = mget(le,ri+1);
            ll hs = mhs.val();
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1; //out(le,ri,hs);
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
        else {
            int le = (i - (mma[i])) / 2;
            int ri = (i + (mma[i])) / 2;
            if (le == ri) continue;
            mint mhs = mget(le,ri+1);
            ll hs = mhs.val();
            if (mmp.find(hs) == mmp.end()){
                mmp[hs] = 1;
                pque.push(pip(mma[i],P(le,ri)));
            }
            else mmp[hs]++;
        }
    }
    while (!pque.empty()){
        auto p = pque.top(); pque.pop();
        if (p.first <= 2) continue;
        int le = p.second.first, ri = p.second.second;
        mint imhs = mget(le,ri+1);
        ll ihs = imhs.val();
        le++, ri--;
        mint mhs = mget(le,ri+1);
        ll hs = mhs.val();
        if (mmp.find(hs) == mmp.end()){
            mmp[hs] = mmp[ihs];//out(le,ri,hs);
            pque.push(pip(p.first-2,P(le,ri)));
        }
        else mmp[hs] += mmp[ihs];
    }
    ll ans = 0;
    for (auto p : nmp){ //out(p.first,p.second);
        if (mmp.find(p.first) == mmp.end()) continue;
        ans += p.second * mmp[p.first]; //out(p.second,mmp[p.first]);
    }
    for (auto q : mmp){
        //out(q.first, q.second);
    }
    out(ans);
}

int main(){
    int t = 1; //cin >> t;
    while (t--) solve();
}
accuracy: 0.06666666666666667
time_ms: 60
memory_kb: 11852
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
const long long BASE = 123456789;
const long long M30 = ((long long) 1 << 30) - 1;
const long long M31 = ((long long) 1 << 31) - 1;
const long long MOD = ((long long) 1 << 61) - 1;
unsigned long long modulo(unsigned long long x){
  unsigned long long xu = x >> 61;
  unsigned long long xd = x & MOD;
  unsigned long long res = xu + xd;
  if (res >= MOD){
    res -= MOD;
  }
  return res;
}
unsigned long long mul(unsigned long long a, unsigned long long b){
  unsigned long long au = a >> 31;
  unsigned long long ad = a & M31;
  unsigned long long bu = b >> 31;
  unsigned long long bd = b & M31;
  unsigned long long mid = au * bd + ad * bu;
  unsigned long long midu = mid >> 30;
  unsigned long long midd = mid & M30;
  return modulo(au * bu * 2 + midu + (midd << 31) + ad * bd);
}
struct rolling_hash{
  vector<long long> POW, S;
  rolling_hash(string s){
    int N = s.size();
    POW.resize(N + 1);
    POW[0] = 1;
    for (int i = 0; i < N; i++){
      POW[i + 1] = mul(POW[i], BASE);
    }
    S.resize(N + 1);
    S[N] = 0;
    for (int i = N - 1; i >= 0; i--){
      S[i] = modulo(mul(S[i + 1], BASE) + s[i]);
    }
  }
  long long get(int L, int R){
    return modulo(S[L] + MOD - mul(S[R], POW[R - L]));
  }
};
vector<int> manacher(string &S){
  int N = S.size();
  vector<int> ans(N, 0);
  int i = 0, j = 0;
  while (i < N){
    while (i >= j && i + j < N && S[i - j] == S[i + j]){
      j++;
    }
    ans[i] = j;
    int k = 1;
    while (i >= k && i + k < N && k + ans[i - k] < j){
      ans[i + k] = ans[i - k];
      k++;
    }
    i += k;
    j -= k;
  }
  return ans;
}
unordered_map<unsigned long long, int> solve(string S){
  int N = S.size();
  string T = "$";
  for (int i = 0; i < N; i++){
    T += S[i];
    T += '$';
  }
  vector<int> A = manacher(T);
  rolling_hash RH(S);
  unordered_map<unsigned long long, int> mp;
  priority_queue<pair<int, int>> pq;
  for (int i = 1; i < N * 2; i++){
    int l = (i - A[i] + 2) / 2, r = (i + A[i] - 1) / 2;
    if (l < r){
      unsigned long long hash = RH.get(l, r);
      if (mp.count(hash) == 0){
        pq.push(make_pair(r - l, l));
      }
      mp[hash]++;
    }
  }
  while (!pq.empty()){
    int L = pq.top().second;
    int R = L + pq.top().first;
    pq.pop();
    unsigned long long hash = RH.get(L, R);
    L++;
    R--;
    if (L < R){
      unsigned long long hash2 = RH.get(L, R);
      if (mp.count(hash2) == 0){
        pq.push(make_pair(R - L, L));
      }
      mp[hash2] += mp[hash];
    }
  }
  return mp;
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  string S;
  cin >> S;
  string T;
  cin >> T;
  unordered_map<unsigned long long, int> A = solve(S);
  unordered_map<unsigned long long, int> B = solve(T);
  long long ans = 0;
  for (auto P : A){
    if (B.count(P.first) == 1){
      ans += (long long) P.second * B[P.first];
    }
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 8848
final_rank: 1