版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/84565034
传送门:bzoj4199
题解
法1(SA):
。
两个串是 相似的,必然也是 相似的。所以求出每两个后缀之前最大是 相似时统计如 的答案后,做个后缀和即可。
将所有点按 排序,逐个枚举分界点 ,求出极大区间 满足 ,分别求出 和 区间对应点的最大和最小美味度(记录最小是因为可能两个负数相乘得到更大的值) 。
按 降序加入点,就是一个并查集的合并区间操作。
法2(SAM):
将串倒序插入
后,按照
链连起来就得到了一颗后缀树,
(
表示以
开始的后缀对应的结点),直接在树上
即可。
代码
SA
#include<bits/stdc++.h>
#define mem(f,x) memset((f),(x),sizeof((f)))
using namespace std;
const int inf=2e9;
typedef long long ll;
const int N=3e5+10;
int tk,n,val[N];char s[N];
ll v[N],f[N];
struct bcj{int fa,mn,mx,sz;}b[N];
struct ht{
int h,x,y;
bool operator<(const ht&ky)const{
return ky.h<h;
}
}q[N];
int getfa(int x){return b[x].fa==x?x:(b[x].fa=getfa(b[x].fa));}
struct SA{
int m,sa[N],t1[N],t2[N],c[N],rk[N],h[N];
inline void build()
{
int i,k,p,*x=t1,*y=t2;m=26;
for(i=1;i<=m;++i) c[i]=0;
for(i=1;i<=n;++i) c[(x[i]=(int)s[i])]++;
for(i=1;i<=m;++i) c[i]+=c[i-1];
for(i=n;i;--i) sa[c[x[i]]--]=i;
for(k=1;k<n;k<<=1){
for(p=0,i=n-k+1;i<=n;++i) y[++p]=i;
for(i=1;i<=n;++i) if(sa[i]>k) y[++p]=sa[i]-k;
for(i=1;i<=m;++i) c[i]=0;
for(i=1;i<=n;++i) c[x[y[i]]]++;
for(i=1;i<=m;++i) c[i]+=c[i-1];
for(i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
p=1;swap(x,y);x[sa[1]]=1;
for(i=2;i<=n;++i){
p+=((y[sa[i]]!=y[sa[i-1]])||(y[sa[i]+k]!=y[sa[i-1]+k]))?1:0;
x[sa[i]]=p;
}
if(p>=n) break;
m=p;
}
}
inline void sol()
{
int i,j,k=0,x,y;
for(i=1;i<=n;++i) rk[sa[i]]=i;
for(i=1;i<=n;++i) b[i]=(bcj){i,val[sa[i]],val[sa[i]],1};
for(i=1;i<=n;++i){
if(rk[i]==1) {k=0;continue;}
if(k) k--;j=sa[rk[i]-1];
for(;j+k<=n && i+k<=n && s[j+k]==s[i+k];++k);
h[rk[i]]=k;
}
for(i=1;i<n;++i) q[i]=(ht){h[i+1],i,i+1};
sort(q+1,q+n);
for(i=q[1].h,j=1;~i;--i){
v[i]=v[i+1];f[i]=f[i+1];
for(;j<n && q[j].h==i;++j){
x=getfa(q[j].x);y=getfa(q[j].y);
v[i]=max(v[i],max((ll)b[x].mx*b[y].mx,(ll)b[x].mn*b[y].mn));
f[i]+=(ll)b[x].sz*b[y].sz;b[y].fa=x;b[x].sz+=b[y].sz;
b[x].mn=min(b[x].mn,b[y].mn);b[x].mx=max(b[x].mx,b[y].mx);
}
}
}
}A;
int main(){
int i;mem(v,0x8f);
scanf("%d%s",&n,s+1);
for(i=1;i<=n;++i) s[i]=s[i]-'a'+1;
for(i=1;i<=n;++i) scanf("%d",&val[i]);
A.build();A.sol();
for(i=0;i<n;++i) printf("%lld %lld\n",f[i],(f[i])?(v[i]):0LL);
return 0;
}