CF1090J Two Prefixes

神仙题++

还是在某校梁大讲的题qaq

我们考虑容斥

也就是本质不同字串=全部-重复的

我们只需要求重复的即可

考虑相同的s=ab 我们用长度最长的a作为代表串

如果存在一个a'b'且|a'|>|a| 分析可以知道必然有b'是b的border 如图

那么显然我们存在b的最长border b''使a''b''=ab

这个可以kmp求得f[i]为border

然后我们在考虑b的一段前缀在a中出现的次数

那么我们可以通过exkmp求得g[i]表示以i开头的最长长度 然后接下来反向前缀和更新即可

一个方便的做法是把s串和t串拼到一起然后做exkmp

还有一个小bug就是memcpy的时候sizeof是一整个数组...不能写一个位置...调了我一上午QAQ

代码参考了bestfy学姐的 非常简洁qwq

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define N 200005
using namespace std;

char ch[N],s[N],t[N];
int f[N],g[N],ans[N];
void kmp(int n)
{
    for(int i=2;i<=n;i++)
    {
        f[i]=f[i-1];
        while(f[i]&&ch[f[i]+1]!=ch[i])    f[i]=f[f[i]];
        f[i]=(ch[f[i]+1]==ch[i]?f[i]+1:f[i]);
    }
}
void exkmp(int n)
{
    int ms=1;
    for(int i=2;i<=n;i++)
    {
        g[i]=max(0,min(g[i-ms+1],ms+g[ms]-i));
        while(i+g[i]<=n&&ch[i+g[i]]==ch[1+g[i]]) g[i]++;
        if(i+g[i]>ms+g[ms]) ms=i;
    }
    g[1]=n;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%s%s",t+1,s+1); int n=strlen(s+1);
    memcpy(ch+1,s+1,sizeof(char)*(n+3)); kmp(n);
    int ls=n,lt=strlen(t+1);// printf("%s",ch+1);
    ch[++n]='*'; for(int i=1;i<=lt;i++)    ch[++n]=t[i];
    exkmp(n);
    for(int i=ls+3;i<=n;i++)    ans[g[i]]++;
    for(int i=ls;i>=1;i--)    ans[i]+=ans[i+1];
    ll fin=1ll*lt*ls;
    for(int i=1;i<=ls;i++)    if(f[i]) fin-=ans[i-f[i]];
    printf("%I64d\n",fin);
    return 0;
}
View Code

 

posted @ 2019-06-28 08:29  寒雨微凝  阅读(518)  评论(0编辑  收藏  举报