跑一遍SAM,然后建一棵线段树,维护最大值和出现次数即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
inline LL C2(LL x){
return (x * (x - 1)) >> 1;
}
const int ALB = 26;
const int maxn =300005;
char c[maxn],d[maxn];
static int cc[maxn];
struct pi{
int le,ri;
long long m,s;
}pp[maxn<<2];
void build(int tot,int l,int r){
pp[tot].le=l;
pp[tot].ri=r;
pp[tot].m=-(LL)1<<60;
pp[tot].s=0;
if(l==r) return;
build(2*tot,l,(l+r)/2);
build(2*tot+1,(l+r)/2+1,r);
}
void merg1(int tot,int l,int r,long long m){
if(pp[tot].le>=l&&pp[tot].ri<=r){
pp[tot].m=max(m,pp[tot].m);
return;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) merg1(2*tot,l,r,m);
if(r>mid){
merg1(2*tot+1,l,r,m);
}
}
void merg2(int tot,int l,int r,long long s){
if(pp[tot].le>=l&&pp[tot].ri<=r){
pp[tot].s+=s;
return;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) merg2(2*tot,l,r,s);
if(r>mid){
merg2(2*tot+1,l,r,s);
}
}
long long query1(int tot,int x){
if(pp[tot].le==pp[tot].ri){
return pp[tot].m;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
long long s=pp[tot].m;
if(x<=mid) return max(s,query1(2*tot,x));
else return max(s,query1(2*tot+1,x));
}
long long query2(int tot,int x){
if(pp[tot].le==pp[tot].ri){
return pp[tot].s;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
long long s=pp[tot].s;
if(x<=mid) return s+query2(2*tot,x);
else return s+query2(2*tot+1,x);
}
struct NODE{
NODE *par, *go[ALB];
int val;
int x;
int y;
int x1,y1;
int size;
NODE(int val):par(NULL),val(val),size(1){
x=-1000000000;
y=-1000000000;
x1=1000000000;
y1=1000000000;
fill_n(go, ALB, (NODE*)NULL);
}
NODE(){};
}node[maxn<<1], *last,*root,*no;
int ncnt;
void Init(){
memset(cc,0,sizeof(cc));
ncnt = 1;
root=&node[0];
*root=NODE(0);
last=root;
}
int a[maxn];
void Append(int x,int qq){
NODE *p = last, *np = &node[ncnt ++];
*np = NODE(p->val + 1);
np->x=qq;
np->x1=qq;
for(; p && !p->go[x]; p = p->par)p->go[x] = np;
if(p){
NODE *q = p->go[x];
if(p->val + 1 == q->val){
np->par = q;
}
else{
NODE *nq = &node[ncnt ++];
*nq = *q;
nq->size = 0;
nq->val = p->val + 1;
nq->x=nq->y=-1000000000;
nq->x1=nq->y1=1000000000;
q->par = nq;
np->par = nq;
for(; p && p->go[x] == q; p = p->par)
p->go[x] = nq;
}
}
else{
np->par = root;
}
last = np;
}
long long s;
void Deal(int N,int u){
int i;
NODE *cur, *p;
static NODE* top[maxn<<1];
for(i = 0; i < ncnt; i ++)
cc[node[i].val] ++;
for(i = 1; i <= N; i ++)
cc[i] += cc[i - 1];
for(i = 0; i < ncnt; i ++)
top[-- cc[node[i].val]] = &node[i];
for(i = ncnt - 1; i > 0; i --){
cur = top[i];
p = cur->par;
p->size += cur->size;
int x=min(p->x,cur->x);
p->x=max(p->x,cur->x);
p->y=max(p->y,max(x,cur->y));
x=max(p->x1,cur->x1);
p->x1=min(p->x1,cur->x1);
p->y1=min(p->y1,min(x,cur->y1));
}
for(i=1;i<ncnt;i++){
cur = top[i];
if(cur->size>1){
int q=0;
if(cur->par!=NULL) q=cur->par->val;
merg1(1,q+1,cur->val,max((LL)cur->x*cur->y,(LL)cur->x1*cur->y1));
merg2(1,q+1,cur->val,(LL)cur->size*(cur->size-1)/2);
}
}
}
int b[maxn];
int fk[26],fq[26],ff[26];
int main()
{
int i,n;
cin>>n;
scanf("%s",d);
for(i=0;i<n;i++) c[i]=d[n-1-i];
Init();
for(i=0;i<n;i++){
scanf("%d",&b[i]);
}
for(i=0;i<n;i++) a[i]=b[n-1-i];
for(i=0;i<n;i++){
Append(c[i]-'a',a[i]);
}
s=0;
build(1,1,n);
Deal(n,0);
long long s=0,s2;
sort(a,a+n);
s=(LL)n*(n-1)/2;
if(n==1) s2=0;
else s2=max((LL)a[n-1]*a[n-2],(LL)a[0]*a[1]);
if(s2==-(LL)1<<60) s2=0;
cout<<s<<" "<<s2<<endl;
for(i=2;i<=n;i++){
long long s,s1;
s1=query1(1,i-1);
s=query2(1,i-1);
if(s1==-(LL)1<<60) s1=0;
printf("%lld %lld\n",s,s1);
}
}