M - Mediocre String Problem( 扩展KMP + Manacher + 差分 )
题意:给出一个串S,和一个串T. 要求 从S串中取一个子串,后面接上T串的一个前缀 组成一个结果串,(要求S串的部分比T串的部分长),结果串是回文串的个数。
思路:
S串贡献的部分 可以分成两部分,S1+S2;
前面的S1 是T部分的反转;
S2 就只能是回文串,因为S串的部分必须比T的多,所以S2长度必须大于等于1
然后我们可以分成两部分,首先先把S中的所有回文串求出,可以用(回文树/马拉车/字符串哈希)
对于每一个回文串,它的左边半径部分都可以作为S1的右端点,除了中心,而且边缘也可以吃到一个
比如 CABABA 其中 回文串中心是第二个A,S1的右端点可以是CAB 注意C也可以的哦
然后找出这个端点剩下的就是求S1和T的lcp的长度了,根据题意每一个长度都一个贡献一个符合要求的答案
针对这个问题 我们可以把S 反转 和T用EXKMP 求lcp (也可以用后缀数组/字符串哈希/exkmp/后缀自动机)
所以 这题的解法大概有(3×3=9 或者3×4=12)种。
注意:使用差分优化,开long long
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2000006;
char s[maxn],ss[maxn],t[maxn];
int nxt[maxn],extend[maxn];
char Ma[maxn*3];
int Mp[maxn*3];
int st[maxn*3];
void get_nxt()
{
int len = strlen(t);
nxt[0] = len;
int j = 0;
while ( j+1<len && t[j]==t[j+1] ) j++;
nxt[1] = j;
int k = 1;
for ( int i = 2; i<len; i++ ) {
int p = nxt[k]+k-1;
int L = nxt[i-k];
if( i+L < p+1 ) nxt[i] = L;
else {
j = max(1ll*0,p-i+1);
while( i+j<len && t[i+j]==t[j] ) j++;
nxt[i] = j;
k = i;
}
}
}
int exkmp()
{
int lens = strlen(s);
int lent = strlen(t);
get_nxt();
int j = 0;
while( j<lens && j<lent && t[j]==s[j] ) j++;
extend[0] = j;
int k = 0;
for( int i = 1; i<lens; i++ ) {
int p = extend[k]+k-1;
int L = nxt[i-k];
if( i+L<p+1 ) extend[i] = L;
else {
j = max(1ll*0,p-i+1);
while( i+j<lens && j<lent && s[i+j]==t[j] ) j++;
extend[i] = j;
k = i;
}
}
}
int Manacher()
{
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;
int 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;
}
}
int ans = 0;
for ( int i=1; i<l; i++ ) { /// 差分统计
st[i]++; st[i+Mp[i]]--;
}
int now = 0;
for ( int i=1; i<l; i++ ) {
now += st[i];
if ( Ma[i]=='#' ) continue ;
if ( now>0 ) ans+=extend[i/2]*now;
}
cout << ans << endl;
}
signed main()
{
scanf("%s %s",ss,t);
int len = strlen(ss);
for ( int i=0; i<len; i++ ) s[i]=ss[len-i-1];
exkmp();
Manacher();
return 0;
}