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

 

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐