传送门:bzoj4199
法1(SA):
l c p ( s u f ( i ) , s u f ( j ) ) = m i n ( h e i g h t [ r k [ i ] + 1 ] , h e i g h t [ r k [ i ] + 2 ] , . . , h e i g h t [ r k [ j ] ] ) , ( r k [ i ] < r k [ j ] ) lcp(suf(i),suf(j))=min(height[rk[i]+1],height[rk[i]+2],..,height[rk[j]]),(rk[i]<rk[j]) lcp(suf(i),suf(j))=min(height[rk[i]+1],height[rk[i]+2],..,height[rk[j]]),(rk[i]<rk[j])。
两个串是 p p p相似的,必然也是 0 , 1 , 2 , . . , p − 1 0,1,2,..,p-1 0,1,2,..,p−1相似的。所以求出每两个后缀之前最大是 p p p相似时统计如 p p p的答案后,做个后缀和即可。
将所有点按 h e i g h t height height排序,逐个枚举分界点 i i i,求出极大区间 [ l i , r i ] [l_i,r_i] [li,ri]满足 m i n k = l i r i h e i g h t [ k ] = h e i g h t [ i ] min_{k=l_i}^{r_i}height[k]=height[i] mink=liriheight[k]=height[i],分别求出 [ l i , i − 1 ] [l_i,i-1] [li,i−1]和 [ i , r i ] [i,r_i] [i,ri]区间对应点的最大和最小美味度(记录最小是因为可能两个负数相乘得到更大的值) m x , m n mx,mn mx,mn。
按 h e i g h t height height降序加入点,就是一个并查集的合并区间操作。
法2(SAM):
将串倒序插入 S A M SAM SAM后,按照 f a i l fail fail链连起来就得到了一颗后缀树, l c p ( i , j ) = L C A ( d e p ( c n t i , c n t j ) ) lcp(i,j)=LCA(dep(cnt_i,cnt_j)) lcp(i,j)=LCA(dep(cnti,cntj))( c n t i cnt_i cnti表示以 i i i开始的后缀对应的结点),直接在树上 d p dp dp即可。
SA
#include
#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;
}