题目链接
题意: 给你两个字符串 s s s和 t t t,对于 t t t中所有的前缀串 k k k,你要在 s s s中找到所有的子串 s i j s_{ij} sij,使得 s i j s_{ij} sij长度大于 k k k,并且将 s i j s_{ij} sij与 k k k拼接后得到的字符串为回文串。问你最终的数量和。
题解:为了让最后的字符串是回文串,对于前缀串
k
k
k,我们要先在
s
s
s中找到与前缀串
k
k
k一样的子串,再向后扩展,使得扩展的那部分字符串为回文串,即可实现。
我们先将
t
t
t进行反转,然后去遍历
s
s
s,那么现在的问题就转换成了找两个字符串的最长后缀(因为对于这部分所有的子串,他们的答案是一样的,所以最后求出来乘以最长后缀的长度就行了)。这里我们用哈希+二分
来实现。
找出最长后缀后,我们假设当前遍历到
s
i
s_i
si,那么接下来我们要求以
s
i
+
1
s_{i+1}
si+1为起点的回文串数量。想到回文串就想到了马拉车
。马拉车可以求以每个点为中心的最长回文半径,那么对于以这个点为终点,以
i
i
i - 最长回文半径
的位置为起点的区间,终点对于这段区间的贡献值为
1
1
1。所以就转化成了区间修改,最终求每个点的权值的差分数组
问题。稍微推一下就能从马拉车字符串推回到原字符串。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=1e6 + 7;
const ull base = 131;
char s[maxn], t[maxn];
char ma[maxn<<1];
ll mp[maxn<<1], paw[maxn];
ull gap[maxn], hashS[maxn], hashT[maxn];
void init() {
gap[0] = 1;
for (int i = 1; i <= 1000000; ++i) {
gap[i] = gap[i - 1] * base;
}
}
void makeHash(char *s, ull *hash) {
int len = strlen(s);
for (int i = 0; i < len; ++i) {
hash[i + 1] = hash[i] * base + (ull)s[i];
}
}
ull getHash(int l, int r, ull *hash) {
return hash[r + 1] - hash[l] * gap[r - l + 1];
}
void manacher(char *s){
int len = strlen(s);
int l=0;
ma[l++]='$';
ma[l++]='#';
for(int i = 0;i < len; ++i){
ma[l++] = s[i];
ma[l++] = '#';
}
ma[l] = 0;
ll mx = 0, id = 0;
for (int i = 0; i < l; ++i){
mp[i] = mx > i? min(mp[2 * id - i], mx - i) : 1;
while (ma[i + mp[i]] == ma[i - mp[i]]) mp[i]++;
if(i + mp[i] > mx){
mx = i + mp[i];
id = i;
}
}
for (int i = 1; i < l; i++) {
paw[(i >> 1) - (mp[i] >> 1)]++;
paw[(i >> 1)]--;
}
for (int i = 1; i < len; ++i) {
paw[i] += paw[i - 1];
}
}
void solve() {
int len = strlen(s);
int lent = strlen(t);
int l, r, mid;
ll ans = 0;
ll maxx;
for (int i = 0; i < len - 1; ++i) {
l = 1, r = i + 1;
maxx = 0;
while (l <= r) {
mid = l + r >> 1;
if (getHash(i - mid + 1, i, hashS) == getHash(lent - mid, lent - 1, hashT)) {
maxx = mid;
l = mid + 1;
}
else r = mid - 1;
}
ans += maxx * paw[i + 1];
}
printf("%lld\n", ans);
}
int main(){
init();
scanf("%s %s", s, t);
reverse(t, t + strlen(t));
manacher(s);
makeHash(s, hashS);
makeHash(t, hashT);
solve();
return 0;
}