题解:P9873 [EC Final 2021] Beautiful String
WZwangchongming · · 题解
题意:定义
有
数据范围:
solution
我不会告诉你部分分怎么写的,我也不会告诉你我eps暴力怎么炸的。
令
题目给定子串模式为 AABCAB,你肯定要找一个枚举点作为突破。而这题的突破点就在于:里面出现了两次 AB。你枚举前一个 AB,为了满足要求,这个 AB 前面的部分要求是这个 AB 的一个前缀,后面只需要隔了至少一个不等于 A 且不等于 B 的间隔,然后再有一个完全一样的东西拼起来即可。
所以做法已经呼之欲出了:枚举 AB 作为整体,如果能检查其前面有多少个其前缀,后面有多少个完全一样的 AB ,那么把这两个值乘法原理乘起来,就是当前枚举的 AB 产生的贡献。
形式化地讲:令
设
至于如何求出
那如何
最后统计时注意
Main Code:
void mian() {
cin >> S;
n = S.length(); S = ' ' + S;
for(int i = n; i; i--)
for(int j = i; j <= n; j++)
if(S[i] == S[j])
lcp[i][j] = lcp[i + 1][j + 1] + 1;
for(int i = 2; i <= n; i++)
for(int j = i + 3; j < n; j++) {
int k = min(j - i - 1, lcp[i][j]);
if(k >= 2) f[i][k]++;
}
for(int i = 2; i <= n; i++)
for(int j = n - 1; j > 1; j--) f[i][j] += f[i][j + 1];
for(int i = 2; i <= n; i++)
for(int j = 1; j <= min(i - 1, n - i + 1); j++)
if(lcp[i - j][i] >= j) g[i][j]++;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) g[i][j] += g[i][j - 1];
long long ans = 0;
for(int i = 2; i <= n; i++)
for(int j = 2; j <= n; j++) ans += 1ll * f[i][j] * g[i][j - 1];
cout << ans << '\n';
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
memset(lcp, 0, sizeof(lcp));
}
当然,其实我还口胡了一个哈希。
对于找在子串
而对于在子串
说不太清楚,应该是对的。