链接:https://www.nowcoder.com/acm/contest/205/H
来源:牛客网
题目描述
终于活成了自己讨厌的样子。
天空仍灿烂,它爱着大海。
你喜欢大海,我爱过你。
世界上充满了巧合。我们把每句话当成一个字符串,我们定义a对b的巧合值为a的最长后缀的长度并且它是恰好是b的前缀,这里的后缀或者前缀包括字符串的本身。
比如字符串“天空仍灿烂她喜欢大海”对“她喜欢大海我不爱她了我爱的只是与她初见时蔚蓝的天空”的巧合值为5,而字符串“她喜欢大海我不爱她了我爱的只是与她初见时蔚蓝的天空”对“天空仍灿烂她喜欢大海”的巧合值为2。
现在给出n个字符串由"ab"构成的字符串s1,s2,...,sn,求出对于所有1≤ i,j≤ n,si对sj的巧合值的和。
输入描述:
第一行一个整数T(T≤ 1000),表示数据组数。
每组数据第一行一个正整数n(1≤ n≤ 1e5)。接下来n行每行一个字符串si,保证字符串由"ab"构成。
保证单组数据有,保证所有数据有。
输出描述:
对于每组数据,输出一个整数,表示答案。
题解:
把所有前缀的hash存在map里面,只要对于每个后缀找到能和他匹配的个数即可。
然后会出现重复的问题,因为只是匹配最大的后缀和前缀。
重复的情况是某一个后缀完全包含另一个后缀,我们只要把串反向后用Kmp求出循环节,就知道当前下标为i的后缀包含了哪个后缀。
那么我们算答案的时候对于当前后缀 只要加上 出现次数 * (长度 - 循环节长度)即可。
卡了一下模1e9 + 7,改成ull自然溢出就过了。
代码:
#include <bits/stdc++.h>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 2e6 + 5;
char s[MAXN];
char *p[MAXN];
int len[MAXN];
#define seed 233
unordered_map<ull, int> q;
ull kpw[MAXN];
ull hs[MAXN];
int f[MAXN];
void getFail(char *P, int m) {
f[0] = f[1] = 0;
for (int i = 1; i < m; i++) {
int j = f[i];
while (j && P[i] != P[j])
j = f[j];
f[i + 1] = (P[i] == P[j]) ? j + 1 : 0;
}
}
ll getHash(int l, int r) {
return hs[r] - hs[l - 1] * kpw[r - l + 1];
}
char t[MAXN];
ll query(char * s, int n) {
memcpy(t, s, n);
reverse(t, t + n);
getFail(t, n);
for (int i = 0; s[i]; i++) hs[i + 1] = hs[i] * seed + s[i] - 'a' + 1;
ll ret = 0;
for (int i = 0; i < n; i++) {
ll val = getHash(i + 1, n);
int num = q[val];
ret += (ll) num * (n - i - f[n - i]);
}
return ret;
}
void init() {
kpw[0] = 1;
for (int i = 1; i < MAXN; i++) kpw[i] = kpw[i - 1] * seed;
}
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int T;
cin >> T;
init();
while(T--) {
int n;
q.clear();
scanf("%d", &n);
int tot = 0;
for (int i = 1; i <= n; i++) {
scanf("%s", s + tot);
p[i] = s + tot;
tot += (len[i] = strlen(s + tot)) + 1;
for (int j = 0; j < len[i]; j++) {
hs[j + 1] = hs[j] * seed + (*(p[i]+j) - 'a') + 1;
q[hs[j + 1]]++;
}
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans += query(p[i], len[i]);
}
printf("%lld\n", ans);
}
return 0;
}