https://codeforces.ml/gym/103118/problem/F

题意:
求有多少对字符串,能拼成一个\(AA\)串。

思路:
拼在一起后再分开,即把一个串的开头分给另一个串作为结尾,或者把一个串的结尾分给另一个串作为开头,使得两个字符串相同。那么对于一个\(ABA\)串来说,其左右两边的子串是相同的,那么和它中间\(B\)串相同的字符串就可以和它拼在一起,产生贡献。

一个字符串可能要给别人字符,也可能要别人给它字符,要分两种情况。注意两串相同的情况,为了避免重复计数,额外算一下就比较方便。

使用哈希判断左右边子串是否相同。这题卡自然溢出和常见模数,直接双哈希就比较稳。

#include <bits/stdc++.h>

using namespace std;
#define endl "\n"
#define pII pair<ll, ll>
typedef long long ll;
const ll base = 131;
const int N = 4e5 + 7;

ll mod[] = {1000000007, 1000000009};
ll has[2][N], gap[2][N];
char s[N];
map<pair<ll, ll>, int> mpTot, mpSeg;

void makeHash(char *s) {
    int len = strlen(s);
    for (int dd = 0; dd <= 1; ++dd) {
        for (int i = 0; i < len; ++i) {
            has[dd][i + 1] = has[dd][i] * base % mod[dd] + (ll)s[i];
            has[dd][i + 1] %= mod[dd];
        }
    }
}

pair<ll, ll> getHash(int l, int r) {
    ll ans0 = has[0][r + 1] + mod[0] - has[0][l] * gap[0][r - l + 1] % mod[0];
    ll ans1 = has[1][r + 1] + mod[1] - has[1][l] * gap[1][r - l + 1] % mod[1];
    return make_pair(ans0 % mod[0], ans1 % mod[1]);
}

void run() {
    int n;
    scanf("%d", &n);
    ll ans = 0;
    while (n--) {
        scanf("%s", s);
        makeHash(s);
        int len = strlen(s);
        pII pi = getHash(0, len - 1);
        ans += mpTot[pi];
        ans += mpSeg[pi];
        mpTot[pi]++;
        for (int i = 1; i < len; ++i) {
            if (i > len - i + 1) break;
            if (getHash(0, i - 1) != getHash(len - i, len - 1)) continue;
            pi = getHash(i, len - i - 1);
            ans += mpTot[pi];
            mpSeg[pi]++;
        }
    }
    printf("%lld\n", ans);
}

int main() {
    gap[0][0] = gap[1][0] = 1;
    for (int dd = 0; dd <= 1; ++dd) {
        for (int i = 1; i < N; ++i) {
            gap[dd][i] = gap[dd][i - 1] * base % mod[dd];
        }
    }
    int t = 1;
    while (t--) run();
    return 0;
}