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;
}