题意
承接上篇题解
考虑两个后缀的(lcp)是什么,是将串反着插入后缀自动机后两个前缀(终止节点)的(lca)!!!于是可以在parent tree上DP了。
比后缀数组又简单又好写跑的还快。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3*1e5+10;
int n,last,tot,cnt;
int head[maxn<<1],size[maxn<<1];
ll inf;
ll a[maxn],val[maxn<<1],maxx[maxn<<1],minn[maxn<<1],ans1[maxn],ans2[maxn];
char s[maxn];
struct edge{int to,nxt;}e[maxn<<1];
struct SAM
{
int fa,len;
int ch[30];
}sam[maxn<<1];
inline ll read()
{
char c=getchar();ll res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
inline void add(int u,int v){e[++cnt].nxt=head[u];head[u]=cnt;e[cnt].to=v;}
inline void sam_init(){sam[0].fa=-1;sam[0].len=0;last=0;}
inline void sam_add(int c,int id)
{
int now=++tot;sam[now].len=sam[last].len+1;size[now]=1;val[now]=a[id];
int p=last;last=now;
while(~p&&!sam[p].ch[c])sam[p].ch[c]=now,p=sam[p].fa;
if(p==-1){sam[now].fa=0;return;}
int q=sam[p].ch[c];
if(sam[q].len==sam[p].len+1)sam[now].fa=q;
else
{
int nowq=++tot;
sam[nowq].len=sam[p].len+1;
memcpy(sam[nowq].ch,sam[q].ch,sizeof(sam[q].ch));
sam[nowq].fa=sam[q].fa,sam[q].fa=sam[now].fa=nowq;
while(~p&&sam[p].ch[c]==q)sam[p].ch[c]=nowq,p=sam[p].fa;
}
}
void dfs(int x)
{
maxx[x]=-inf,minn[x]=inf;
if(size[x])maxx[x]=minn[x]=val[x];
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
dfs(y);
if(minn[x]!=inf&&minn[y]!=inf&&maxx[x]!=-inf&&maxx[x]!=-inf)
ans2[sam[x].len]=max(ans2[sam[x].len],max(maxx[x]*maxx[y],minn[x]*minn[y]));
maxx[x]=max(maxx[x],maxx[y]),minn[x]=min(minn[x],minn[y]);
ans1[sam[x].len]+=1ll*size[x]*size[y];
size[x]+=size[y];
}
}
int main()
{
n=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)a[i]=read();
sam_init();
for(int i=n;i;i--)sam_add(s[i]-'a',i);
for(int i=1;i<=tot;i++)add(sam[i].fa,i);
memset(ans2,-0x3f,sizeof(ans2));inf=-ans2[0];
dfs(0);
for(int i=n-1;~i;i--)ans1[i]+=ans1[i+1],ans2[i]=max(ans2[i],ans2[i+1]);
for(int i=0;i<n;i++)
if(ans1[i])printf("%lld %lld
",ans1[i],ans2[i]);
else puts("0 0");
return 0;
}