容易发现,我们只需要求出(最多r)相似(r=0~n-1)的对数,就可以用前缀和算出r相似的对数。
最多r相似的统计可以用后缀数组的h数组来统计。将每一对酒分类为r被h[2]卡住了,被h[3]卡住啦。。。。
那么就需要求出每一个h[i],最大的区间[a,b]使得
h
[
i
]
=
m
i
n
i
=
a
b
(
h
[
i
]
)
h[i] = min_{i=a}^b(h[i])
h[i]=mini=ab(h[i])
然后被i卡住的对数就是
(
i
−
a
)
∗
(
b
+
1
−
i
)
(i-a) * (b+1-i)
(i−a)∗(b+1−i)(h[i]的意义是sa[i]与sa[i-1]的最长公共前缀)
再RMQ预处理一下同样区间求最小值最大值就可以得到最大乘积了。
AC Code:
#include<bits/stdc++.h>
#define maxn 300005
#define LL long long
using namespace std;
int n;
LL cnt[maxn],Max[maxn];
int a[maxn],sa[maxn],rk[maxn],h[maxn],wa[maxn],wb[maxn],c[maxn],st[2][19][maxn],lg[maxn];
char s[maxn];
void Build(int n,int m)
{ int *x=wa,*y=wb,i,j,p,k=0;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(j=1,p=0;j<n && p<n;j<<=1,m=p)
{ for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
for(swap(x,y),i=1,p=1,x[sa[0]]=0;i<n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++;}
for(i=0;i<n;i++) rk[sa[i]]=i;
for(i=0;i<n-1;h[rk[i++]]=k)
for(k?k--:0;s[i+k]==s[sa[rk[i]-1]+k];k++);
}
inline int query_max(int a,int b)
{ int tmp = lg[b-a+1];
return max(st[0][tmp][a],st[0][tmp][b-(1<<tmp)+1]);}
inline int query_min(int a,int b)
{ int tmp = lg[b-a+1];
return min(st[1][tmp][a],st[1][tmp][b-(1<<tmp)+1]);}
deque<int>q;
int f[maxn];
int main()
{
scanf("%d",&n);
scanf("%s",s);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=2;i<=n;i++) lg[i] = lg[i>>1]+1;
Build(n+1,200);
for(int i=1;i<=n;i++) st[0][0][i] = st[1][0][i] = a[sa[i]+1];
for(int j=1;j<19;j++)
for(int i=1;i<=n;i++)
if(i+(1<<j-1) <= n)
st[0][j][i] = max(st[0][j-1][i],st[0][j-1][i+(1<<j-1)]),
st[1][j][i] = min(st[1][j-1][i],st[1][j-1][i+(1<<j-1)]);
memset(Max,-0x3f,sizeof Max);
for(int i=2;i<=n+1;i++)
{
f[i]=i-1;
for(;!q.empty() && h[q.back()]>=h[i];q.pop_back())
{
cnt[h[q.back()]] += 1ll * (q.back()-f[q.back()]) * (i - q.back());
Max[h[q.back()]] =
max(Max[h[q.back()]] ,
max(1ll * query_max(f[q.back()],q.back()-1)*query_max(q.back(),i-1),
1ll * query_min(f[q.back()],q.back()-1)*query_min(q.back(),i-1))
);
f[i] = f[q.back()];
}
q.push_back(i);
}
for(int i=n;i>=0;i--) cnt[i]+=cnt[i+1] , Max[i] = max(Max[i],Max[i+1]);
for(int i=0;i<n;i++) printf("%lld %lld\n",cnt[i],cnt[i]?Max[i]:0);
}