神仙题++
还是在某校梁大讲的题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
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
//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; }