题目
求所有 l e n len len长公共前缀的两子串的方案数和对应权值最大值
题解
容易想到后缀数组用
h
e
i
g
h
t
height
height查
l
c
p
lcp
lcp
因为如果两子串有
l
e
n
len
len长公共前缀,则
1
,
2...
,
l
e
n
−
1
1,2...,len-1
1,2...,len−1都成立
数据结构什么的很烦人,我们就差分吧,查两子串最长的公共前缀,最后倒着累加起来
方案数比较简单,用找不同子串的方式,单调栈,将方案数累加到
a
n
s
1
[
h
e
i
g
h
t
[
i
]
]
ans1[height[i]]
ans1[height[i]]
最大值的话,需要同时维护最大和最小(因为还有负数)
在每个找方案数对应区间里找两个相乘最大,也可以在单调栈里多维护几个数组
注意对应过去的权值是
v
a
l
[
s
a
[
i
]
]
val[sa[i]]
val[sa[i]]
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10;
const ll INF=1e18+10;
int n,m;
char s[N];
int tp[N],rk[N],sa[N],t[N];
void Qsort()
{
for(int i=1;i<=m;i++)t[i]=0;
for(int i=1;i<=n;i++)t[rk[i]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i>=1;i--)sa[t[rk[tp[i]]]--]=tp[i];
}
void SA()
{
for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;m=30;Qsort();
for(int w=1,p;w<=n;m=p,w<<=1)
{
p=0;
for(int i=n-w+1;i<=n;i++)tp[++p]=i;
for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
Qsort();swap(tp,rk);p=rk[sa[1]]=1;
for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
if(p==n)return ;
}
}
int h[N];
void get_h()
{
int k=0;
for(int i=1;i<=n;i++)
{
if(rk[i]==1)continue;
int j=sa[rk[i]-1];if(k)k--;
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
h[rk[i]]=k;
}
}
ll a[N];
ll ans1[N],ans2[N];
int z[N],p;
ll minn[N],maxx[N];
int L[N],R[N];
void work()
{
ll ma=-INF,mi=INF;
for(int i=1;i<=n;i++)ans2[i]=LLONG_MIN;
z[++p]=1;
for(int i=2;i<=n;i++)
{
ma=mi=a[sa[i-1]];
while(p&&h[z[p]]>h[i])
{
ans2[h[z[p]]]=max(ans2[h[z[p]]],max(1ll*maxx[p]*ma,1ll*minn[p]*mi));
ma=max(ma,maxx[p]);mi=min(mi,minn[p]);
R[z[p--]]=i;
}
L[i]=z[p];
z[++p]=i;minn[p]=mi,maxx[p]=ma;
}
ma=mi=a[sa[n]];
while(p)
{
ans2[h[z[p]]]=max(ans2[h[z[p]]],max(1ll*maxx[p]*ma,1ll*minn[p]*mi));
ma=max(ma,maxx[p]);mi=min(mi,minn[p]);
R[z[p--]]=n+1;
}
for(int i=2;i<=n;i++)ans1[h[i]]+=(ll)(R[i]-i)*(i-L[i]);
for(int i=n-2;i>=0;i--)
{
ans1[i]+=ans1[i+1];
ans2[i]=max(ans2[i],ans2[i+1]);
}
}
int main()
{
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
SA();get_h();
work();
for(int i=0;i<n;i++)
{
printf("%lld %lld\n",ans1[i],ans1[i]==0?0:ans2[i]);
}
}