题目等价于求任意两对后缀的LCP的值小于等于1,2…n的个数,以及权值乘积的最大值。
求出后缀数组的height值,然后预处理出每个height值能够成为最小的区间。
考虑每个height的值对答案的贡献:如果height[i]能够成为最小的区间为[L,R],那么个数便是(L-i+1)*(R-i+1)。而乘积最大值则一定是max[L,i-1]*max[i,R]或者min[L,i-1]*min[i,R](有可能是负数),用rmq预处理一下就可以。
(当时全场200多个人过了这题,而我写了一个下午。。。。。跪跪跪)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <deque>
#include <queue>
#include <map>
#include <set>
#include <ctime>
#define putarray(a,n) for (int i=1;i<=n-1;i++) printf("%d ",a[i]); printf("%d\n",a[n]);
using namespace std;
typedef long long ll;
const int MAXN=300005,INF=(1<<30);
int n,A[MAXN],L[MAXN],R[MAXN]; char str[MAXN];
ll ans[MAXN],cnt[MAXN];
ll gmax(ll a,ll b) { if (a>b) return a; return b; }
class RMQ
{
int lim,mn[MAXN][20],mx[MAXN][20];
public:
void init(int *a)
{
lim=int(log2(n)+1);
for (int i=1;i<=n;i++) mn[i][0]=mx[i][0]=a[i];
for (int j=1;j<=lim;j++)
for (int i=1;i<=n;i++)
{
int p=i+(1<<(j-1));
if (i+(1<<j)-1>n)
{
mn[i][j]=INF,mx[i][j]=-INF;
continue;
}
mn[i][j]=min(mn[i][j-1],mn[p][j-1]),mx[i][j]=max(mx[i][j-1],mx[p][j-1]);
}
}
int Askmin(int L,int R)
{
int k=int(log2(R-L+1));
return min(mn[L][k],mn[R-(1<<k)+1][k]);
}
int Askmax(int L,int R)
{
int k=int(log2(R-L+1));
return max(mx[L][k],mx[R-(1<<k)+1][k]);
}
}Rmq;
class Suffix_array
{
int sa[MAXN],rank[MAXN],height[MAXN],C[MAXN];
void build_sa(int m)
{
int *x=rank,*y=height;
for (int i=0;i<=m;i++) C[i]=0;
for (int i=1;i<=n;i++) x[i]=int(str[i]-96),C[x[i]]++;
for (int i=1;i<=m;i++) C[i]+=C[i-1];
for (int i=1;i<=n;i++) sa[C[x[i]]--]=i;
for (int k=1;k<=n;k<<=1)
{
int p=0;
for (int i=n-k+1;i<=n;i++) y[++p]=i;
for (int i=1;i<=n;i++) if (sa[i]>k) y[++p]=sa[i]-k;
for (int i=0;i<=m;i++) C[i]=0;
for (int i=1;i<=n;i++) C[x[y[i]]]++;
for (int i=1;i<=m;i++) C[i]+=C[i-1];
for (int i=n;i>=1;i--) sa[C[x[y[i]]]--]=y[i];
swap(x,y); p=1; x[sa[1]]=1;
for (int i=2;i<=n;i++)
if (y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=p;else x[sa[i]]=++p;
if (p==n) break;
m=p;
}
}
void build_height()
{
int k=0;
for (int i=1;i<=n;i++) rank[sa[i]]=i;
for (int i=1;i<=n;i++)
{
if (rank[i]==1) { k=height[rank[i]]=0; continue; }
if (k) k--; int j=sa[rank[i]-1];
while (str[i+k]==str[j+k]) k++;
height[rank[i]]=k;
}
}
public:
void init()
{
for (int i=n;i;i--) str[i]=str[i-1]; str[n+1]='#';
build_sa(26);
build_height();
}
void solve()
{
for (int i=0;i<=n;i++) C[rank[i]]=A[i],cnt[i]=0,ans[i]=-ll(INF)*ll(INF);
Rmq.init(C);
for (int i=1;i<=n;i++)
{
L[i]=i-1;
while (height[i]<height[L[i]] && L[i]) L[i]=L[L[i]]-1;
L[i]++;
}
for (int i=n;i>=1;i--)
{
R[i]=i+1;
while (height[i]<=height[R[i]] && R[i]<=n) R[i]=R[R[i]]+1;
R[i]--;
}
for (int i=2;i<=n;i++)
{
cnt[height[i]]+=ll(i-L[i]+1)*ll(R[i]-i+1);
ans[height[i]]=gmax(ans[height[i]],gmax(ll(Rmq.Askmin(L[i]-1,i-1))*ll(Rmq.Askmin(i,R[i])),
ll(Rmq.Askmax(L[i]-1,i-1))*ll(Rmq.Askmax(i,R[i]))));
}
}
}SA;
int Get()
{
char ch; int v=0; bool f=false;
while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48;
while (isdigit(ch=getchar())) v=v*10+ch-48;
if (f) return -v;else return v;
}
int main()
{
//freopen("savour.in","r",stdin);
//freopen("savour.out","w",stdout);
n=Get(); scanf("%s",str);
for (int i=1;i<=n;i++) A[i]=Get();
SA.init();
SA.solve();
for (int i=n-1;i>=0;i--) cnt[i]+=cnt[i+1],ans[i]=max(ans[i],ans[i+1]);
for (int i=0;i<=n-1;i++)
{
if (ans[i]==-ll(INF)*ll(INF)) ans[i]=0;
printf("%lld %lld\n",cnt[i],ans[i]);
}
return 0;
}