传送门
题意:给一个串,每个位置有一个权值,当 S [ s . . . s + l e n − 1 ] = S [ t . . . t + l e n − 1 ] & & S [ s . . . s + l e n ] ̸ = S [ t . . t + l e n ] S[s...s+len-1]=S[t...t+len-1]\&\&S[s...s+len]\not=S[t..t+len] S[s...s+len−1]=S[t...t+len−1]&&S[s...s+len]̸=S[t..t+len]时我们称两个字串是" l e n len len“相似的,而这对字串的价值等于 a s ∗ a t a_s*a_t as∗at,现在问对于 i = 0 → n − 1 i=0\rightarrow n-1 i=0→n−1,有多少对” i i i"相似字串,以及这几对串的价值的最大值是多少。
思路:
我们把 s a m sam sam建出来,然后在后缀链接树上面树形 d p dp dp出子树的 s i z e , m a x , s e c o n d _ m x , m i n , s e c o n d _ m i n size,max,second\_mx,min,second\_min size,max,second_mx,min,second_min来更新长度在 [ l e n f a + 1 , l e n p ] [len_{fa}+1,len_p] [lenfa+1,lenp]之间的答案。
这个可以用线段树维护。
代码:
#include
#define ri register int
using namespace std;
inline int read(){
int ans=0;
bool f=1;
char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return f?ans:-ans;
}
const int N=3e5+5,M=6e5+5;
typedef long long ll;
const ll inf=1e18;
int n,m,a[N];
namespace SGT{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
ll sum[N<<2],mx[N<<2];
inline void build(int p,int l,int r){
sum[p]=0,mx[p]=-inf;
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
inline void updsum(int p,int l,int r,int ql,int qr,ll v){
if(ql<=l&&r<=qr){sum[p]+=v;return;}
if(qr<=mid)updsum(lc,l,mid,ql,qr,v);
else if(ql>mid)updsum(rc,mid+1,r,ql,qr,v);
else updsum(lc,l,mid,ql,qr,v),updsum(rc,mid+1,r,ql,qr,v);
}
inline void updmax(int p,int l,int r,int ql,int qr,ll v){
if(ql<=l&&r<=qr){mx[p]=max(mx[p],v);return;}
if(qr<=mid)updmax(lc,l,mid,ql,qr,v);
else if(ql>mid)updmax(rc,mid+1,r,ql,qr,v);
else updmax(lc,l,mid,ql,qr,v),updmax(rc,mid+1,r,ql,qr,v);
}
inline void query(int p,int l,int r,ll v1,ll v2){
v1+=sum[p],v2=max(v2,mx[p]);
if(l==r){if(l^n)cout<<v1<<' '<<(v2+inf?v2:0)<<'\n';return;}
query(lc,l,mid,v1,v2),query(rc,mid+1,r,v1,v2);
}
#undef lc
#undef rc
#undef mid
}
namespace sam{
int son[M][26],len[M],link[M],siz[M],last=1,tot=1;
ll mx[M],smx[M],mn[M],smn[M],sum[M];
inline void init(){
memset(siz,0,sizeof(siz));
memset(mx,-0x7f,sizeof(mx)),memset(smx,-0x7f,sizeof(smx));
memset(mn,0x7f,sizeof(mx)),memset(smn,0x7f,sizeof(smn));
}
inline void insert(const int&x,const int&id){
int p=last,np=++tot;
siz[np]=1,len[last=np]=len[p]+1;
mx[np]=mn[np]=a[id];
while(p&&!son[p][x])son[p][x]=np,p=link[p];
if(!p){link[np]=1;return;}
int q=son[p][x],nq;
if(len[q]==len[p]+1){link[np]=q;return;}
len[nq=++tot]=len[p]+1,link[nq]=link[q],link[q]=link[np]=nq;
memcpy(son[nq],son[q],sizeof(son[q]));
while(p&&son[p][x]==q)son[p][x]=nq,p=link[p];
}
inline void pre(){
static int rk[N<<1],cnt[N<<1];
for(ri i=1;i<=tot;++i)++cnt[len[i]];
for(ri i=1;i<=tot;++i)cnt[i]+=cnt[i-1];
for(ri i=tot;i;--i)rk[cnt[len[i]]--]=i;
SGT::build(1,1,n);
for(ri i=tot,p,fa;i^1;--i){
p=rk[i],fa=link[p];
siz[fa]+=siz[p];
if(smx[p]>mx[fa])smx[fa]=mx[fa],mx[fa]=smx[p];
else smx[fa]=max(smx[fa],smx[p]);
if(mx[p]>mx[fa])smx[fa]=mx[fa],mx[fa]=mx[p];
else smx[fa]=max(smx[fa],mx[p]);
if(smn[p]<mn[fa])smn[fa]=mn[fa],mn[fa]=smn[p];
else smn[fa]=min(smn[fa],smn[p]);
if(mn[p]<mn[fa])smn[fa]=mn[fa],mn[fa]=mn[p];
else smn[fa]=min(smn[fa],mn[p]);
SGT::updsum(1,1,n,len[fa]+1,len[p],(ll)siz[p]*(siz[p]-1)/2);
SGT::updmax(1,1,n,len[fa]+1,len[p],max((mx[p]-mx[0]&&smx[p]-smx[0])?mx[p]*smx[p]:-inf,(mn[p]-mn[0]&&smn[p]-smn[0])?mn[p]*smn[p]:-inf));
}
}
}
char s[N];
int main(){
n=read();
scanf("%s",s+1),reverse(s+1,s+n+1);
for(ri i=1;i<=n;++i)a[i]=read();
reverse(a+1,a+n+1),sam::init();
for(ri i=1;i<=n;++i)sam::insert(s[i]-'a',i);
sam::pre(),sort(a+1,a+n+1);
cout<<(ll)n*(n-1)/2<<' '<<max((ll)a[1]*a[2],(ll)a[n]*a[n-1])<<'\n';
SGT::query(1,1,n,0,-inf);
return 0;
}