2018-2019 ACM-ICPC, Asia Nanjing Regional Contest M

扩展KMP+马拉车回文串

s:ababa

t:aba

题意:将第一个字符串的一个字串,与第二个字符串从 (0-k)的字符连在一起可以成为回文字符串,且第一个字符串字串的长度比第二个字符串的长度要大。

要构成的的回文字符串 两部分构成   s' 第一个字符串的字串,和第二个字符串的前缀t',构成一个回文字符串。

那么如果把第一个字符串倒过来, 那就相当于,s' 的一部分是和 t'是相同的,s'还有一部分是回文字符串。

那么s'与t'相同的长度   * 从当前位置能够产生的回文串数量,就相当能够构成的回文串个数。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define debug(x) cout<<"["<<x<<"]"<<endl;
const int maxn=1e6+5;
int nxt[maxn*2],ex[maxn*2];
void getnext(char * str) {
    int i=0,j,po,len=strlen(str);
    nxt[0]=len;
    while(i+1<len&&str[i]==str[i+1])i++;
    nxt[1]=i;
    po=1,j=0;
    for(i=2; i<len; i++) {
        int p=nxt[po]+po;
        if(nxt[i-po]+i<p) {
            nxt[i]=nxt[i-po];
        } else {
            j=p-i;
            if(j<0)j=0;
            while(i+j<len&&str[j]==str[j+i]) j++;
            nxt[i]=j;
            po=i;
        }
    }
}

void exkmp(char *s1,char *s2) {
    int i=0,j,po,len=strlen(s1),l2=strlen(s2);
    getnext(s2);
    while(s1[i]==s2[i]&&i<l2&&i<len)i++;
    ex[0]=i;
    po=0;
    for(i=1; i<len; i++) {
        int p=ex[po]+po;
        if(nxt[i-po]+i<p) {
            ex[i]=nxt[i-po];
        } else {
            j=max(0,p-i);
            while(i+j<len&&j<l2&&s1[i+j]==s2[j]) {
                j++;
            }
            ex[i]=j;
            po=i;
        }
    }
}

char Ma[maxn*2];
int Mp[maxn*2],pos[maxn*2];
int dp[maxn*2],cnt[maxn];
void Manacher(char s[],int len) {   //一名大佬的写法0.0
    memset(pos,-1,sizeof(pos));
    int l=0;
    Ma[l++]='$';
    Ma[l++]='#';
    for(int i=0; i<len; i++) {
        pos[l]=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?std::min(Mp[2*id-i],mx-i):1;
        while(i-Mp[i]>=0&&Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;
        if(i+Mp[i]>mx) {
            mx=i+Mp[i];
            id=i;
        }
    }
    for(int i=0; i<l; i++) {
        dp[i+Mp[i]-1]++;
        if(i>0) dp[i-1]--;
    }
    for(int i=l-1; i>=0; i--) {
        dp[i]+=dp[i+1];
    }
    for(int i=0; i<l; i++) {
        if(pos[i]==-1) continue;
        cnt[pos[i]]=dp[i];
    }
}
char s[maxn],c[maxn];
int main() {
    scanf("%s%s",s,c);
    int len=strlen(s);
    reverse(s,s+len);
    Manacher(s,len);
    exkmp(s,c);
    LL ans=0;
    for(int i=1; i<len; i++) {
        ans+=1LL*cnt[i-1]*ex[i];
    }
    printf("%lld\n",ans);
    return 0;
}