首先我们考虑对于一个点对(i,j)(i,j)(i,j)来说,要找到前面极长的匹配aaa,后面极长的匹配bbb,贡献是两者长度的乘积(a+1)∗(b+1)(a+1)*(b+1)(a+1)∗(b+1),我们考虑在SAM上(i+p,j+p),p∈[0,b](i+p,j+p),p\in[0,b](i+p,j+p),p∈[0,b]两个endposendposendpos合并时统计(i,j)(i,j)(i,j)的贡献。
由于后缀自动机上两个endposendposendpos的LCALCALCA的maxlenmaxlenmaxlen就是对应两个前缀的最长公共后缀,所以我们可以肯定的是,当(i+p,j+p)(i+p,j+p)(i+p,j+p)合并时,设对应点的maxlenmaxlenmaxlen为ccc,(i+p−c+1,j+p−c+1)=(i−a,j−a)(i+p-c+1,j+p-c+1)=(i-a,j-a)(i+p−c+1,j+p−c+1)=(i−a,j−a)
(i,j)(i,j)(i,j)会被b+1b+1b+1种点对统计到,我们只需要在每一次被统计到时给答案加上a+1a+1a+1就可以了。在SAMSAMSAM节点上,贡献和相当于每次加一个等差数列。
这时候没有k1,k2k1,k2k1,k2限制的答案已经出来了。
考虑上k2k2k2的限制,我们发现只要限制一下每次加的等差数列的末项不大于k2k2k2就可以了。
k1k1k1的限制怎么办,对于一个SAMSAMSAM上的节点,我们看是否存在被恰好计算第k1+1k1+1k1+1次的节点,如果存在,那么减去其产生的所有贡献。同时,这个还限制了等差数列的首项不小于maxleni−k1+1maxlen_i-k1+1maxleni−k1+1。具体可以看看代码怎么写。
好像我的做法与其他题解不大相同,同时也以90ms90ms90ms的运行时间成为了题解提交时间为止的最优解。
代码十分简洁明了,个人在处理SAMSAMSAM上failfailfail树合并问题时钟爱对长度基数排序。
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int fail[N],ch[N][26],mx[N],n,k1,k2,las,rig[N],sum[N],a[N],tot;
unsigned long long op[N],ans;
char s[N];
void insert(int c){
int x=++tot,p=las;las=x;mx[x]=mx[p]+1;rig[x]=1;
for(;p!=-1 && !ch[p][c];p=fail[p]) ch[p][c]=x;
if(p==-1) fail[x]=0;
else if(mx[ch[p][c]]==mx[p]+1) fail[x]=ch[p][c];
else{
int q=++tot,tmp=ch[p][c];mx[q]=mx[p]+1;
fail[q]=fail[tmp];fail[x]=fail[tmp]=q;
for(int i=0;i<26;i++) ch[q][i]=ch[tmp][i];
for(;p!=-1 && ch[p][c]==tmp;p=fail[p]) ch[p][c]=q;
}
}
unsigned long long gs(int x,int y){
if(x>y) return 0;
return 1ull*(x+y)*(y-x+1)/2;
}
int main(){
scanf("%s",s+1);n=strlen(s+1);
scanf("%d %d",&k1,&k2);fail[0]=-1;
for(int i=1;i<=n;i++) insert(s[i]-'a');
for(int i=1;i<=tot;i++) sum[mx[i]]++;
for(int i=n;i>=1;i--) sum[i]+=sum[i+1];
for(int i=1;i<=tot;i++) a[sum[mx[i]]--]=i;
for(int i=1;i<=tot;i++){
int x=a[i];
op[fail[x]]+=1ull*rig[x]*rig[fail[x]];
rig[fail[x]]+=rig[x];
ans+=op[x]*gs(max(1,mx[x]-k1+1),min(k2,mx[x]));
if(mx[x]>k1 && mx[x]-k1<=k2) ans-=1ull*op[x]*(mx[x]-k1)*k1;
}
printf("%llu\n",ans);
}
本文介绍了如何通过前缀自动机(Suffix Automaton, SAM)快速计算文本中点对的贡献,特别关注了k1和k2限制下的等差数列求和问题。作者的方法独特,以90ms的高效运行时间解决挑战,核心在于基数排序处理SAM节点合并和贡献计算。
1万+

被折叠的 条评论
为什么被折叠?



