Luogu5115 Check,Check,Check one two!
Luogu5115 Check,Check,Check one two!
重工业边分树不说了。
考虑对于一个\(i,j\)来说,\(\operatorname{lcp}(i,j),\operatorname{lcs}(i,j)\)有什么性质。
\[S(i-\operatorname{lcp}(i,j)+1,i+\operatorname{lcs}(i,j)-1)=S(j-\operatorname{lcp}(i,j)+1,j+\operatorname{lcs}(i,j)-1)
\]
那么我们考虑两个相同的子串\(S(l_1,r_1),S(l_2,r_2)\),在什么情况下会对答案产生贡献呢?
\[S_{l1-1} \ne S_{l_2-1} \\
S_{r_1+1} \ne S_{r_2+1}
\]
这是由于\(\operatorname{lcp},\operatorname{lcs}\)的限制所决定的。
在这个串中满足长度限制的位置都会产生贡献,可以利用计数公式\(O(1)\)计算预处理。
我们考虑在\(SAM\)上完成这个事情,我们把子串在\(parent\)树\(LCA\)处统计所有前缀的贡献,那么统计贡献时左端点必然无法延伸。
然后是右端点,我们肯定选取的是当前节点代表的最长子串,然后试图在后面加字符。我们只需要记录所有前缀中后面可加入字符\(c\)的方案数,然后用总方案数减去所有可以添加相同字符的方案即可。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define ull unsigned long long
using namespace std;
int n,k1,k2;
int cnt=1,lst=1,tr[N << 1][26],len[N << 1],pre[N << 1];
int c[N],a[N << 1],sz[N << 1],num[N << 1][26];
char s[N];
ull ans=0,clc[N];
ull calc1(int n)
{
return (ull)n*(n+1)/2;
}
ull calc2(int n)
{
return (ull)n*(n+1)*(n+n+1)/6;
}
void preparation()
{
for (int i=1;i<=n;++i)
{
int l=max(1,i-k2+1),r=min(i,k1);
if (l<=r)
clc[i]=(ull)(i+1)*(calc1(r)-calc1(l-1))-(calc2(r)-calc2(l-1));
}
}
void ins(int c,int i)
{
int p=lst,np=++cnt;
lst=np,len[np]=len[p]+1,sz[np]=1;
if (i!=n)
num[np][s[i+1]-'a']=1;
for (;p && !tr[p][c];p=pre[p])
tr[p][c]=np;
if (!p)
pre[np]=1; else
{
int q=tr[p][c];
if (len[p]+1==len[q])
pre[np]=q; else
{
int g=++cnt;
memcpy(tr[g],tr[q],sizeof(tr[q]));
len[g]=len[p]+1,pre[g]=pre[q];
for (;p && tr[p][c]==q;p=pre[p])
tr[p][c]=g;
pre[np]=pre[q]=g;
}
}
}
int main()
{
scanf("%s",s+1),n=strlen(s+1);
scanf("%d%d",&k1,&k2);
preparation();
for (int i=1;i<=n;++i)
ins(s[i]-'a',i);
for (int i=1;i<=cnt;++i)
++c[len[i]];
for (int i=1;i<=n;++i)
c[i]+=c[i-1];
for (int i=cnt;i;--i)
a[c[len[i]]--]=i;
for (int i=cnt;i>=2;--i)
{
int u=a[i];
ull o=(ull)sz[u]*sz[pre[u]];
for (int j=0;j<26;++j)
o-=(ull)num[u][j]*num[pre[u]][j];
ans+=o*clc[len[pre[u]]];
sz[pre[u]]+=sz[u];
for (int j=0;j<26;++j)
num[pre[u]][j]+=num[u][j];
}
printf("%llu\n",ans);
return 0;
}