bzoj上没有题面。。(百度有hhh)
这看上去就很后缀数组啊。。
先处理出后缀数组(都快忘了咋整了)。。
也就是处理出sa,rank,height三个数组
由后缀数组的性质,两个后缀的LCP是路径上height值取min
第i个位置的height值,能用作LCP的区间[L,R],满足区间最小height为height[i]
那么在[L,i)中选一位置为左端点,在[i,R]中选一位置作右端点,LCP = height[i]
可以用单调队列求出每个位置能使用的区间[L,R]
小心重复计算
可以这样,对于位置i,使劲向右找,直到找到一个位置k,height[k] < height[i],用k - 1作右端点
对于位置i,使劲向左找,直到找到一个位置k,height[k] <= height[i],用k + 1作左端点
处理出了所有的L[i],R[i],第一个询问就简单了,乘一下即可
第二个询问,可以查询出左边的最大最小值,有边的最大最小值,瞎逼乘一乘,
苟蒻强行套一个RMQ,其实可以线性,不过这样好写。。。
于是常数巨大233
此题边界略啰嗦。。。。调了有点久
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 3E5 + 30;
typedef long long LL;
int n,top,s[maxn],sa[maxn],rank[maxn],Min[maxn][20],Max[maxn][20]
,L[maxn],R[maxn],height[maxn],t[maxn],t2[maxn],c[maxn];
LL a1[maxn],a2[maxn],mi[2],ma[2],a[maxn],b[maxn];
char ch[maxn];
void Getsa()
{
int *x = t,*y = t2,m = 26;
for (int i = 1; i <= n; i++) ++c[x[i] = ch[i]];
for (int i = 2; i <= m; i++) c[i] += c[i-1];
for (int i = n; i; i--) sa[c[x[i]]--] = i;
for (int k = 1; k < n; k <<= 1) {
int p = 0;
for (int i = n; i > n - k; i--) y[++p] = i;
for (int i = 1; i <= n; i++) if (sa[i] - k > 0) y[++p] = sa[i] - k;
for (int i = 1; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) ++c[x[y[i]]];
for (int i = 2; i <= m; i++) c[i] += c[i-1];
for (int i = n; i; i--) sa[c[x[y[i]]]--] = y[i];
swap(x,y); p = 1; x[sa[1]] = 1;
for (int i = 2; i <= n; i++)
x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]?p:++p;
m = p;
if (m >= n) return;
}
}
void Rank_and_Height()
{
for (int i = 1; i <= n; i++) rank[sa[i]] = i;
int k = 0;
for (int i = 1; i <= n; i++) {
if (k) --k;
while (ch[i+k] == ch[sa[rank[i]-1]+k]) ++k;
height[rank[i]] = k;
}
}
void Query(int l,int r,int k)
{
if (l > r) return;
int len = r - l + 1,t = 0;
while (l + (1<<t) - 1 <= r) ++t; --t;
mi[k] = min(Min[l][t],Min[r - (1<<t) + 1][t]);
ma[k] = max(Max[l][t],Max[r - (1<<t) + 1][t]);
}
void Pre_Work()
{
for (int i = 1; i <= n; i++)
b[i] = Min[i][0] = Max[i][0] = a[sa[i]];
for (int j = 1; j < 20; j++)
for (int i = 1; i <= n; i++) {
int t = i + (1<<(j-1));
if (t > n) break;
Max[i][j] = max(Max[i][j-1],Max[t][j-1]);
Min[i][j] = min(Min[i][j-1],Min[t][j-1]);
}
}
void Print()
{
for (int i = 1; i <= n; i++) {
for (int j = sa[i]; j <= n; j++)
putchar(ch[j] + 'a' - 1);
puts("");
}
}
LL getLL()
{
char ch = getchar();
LL ret = 0,A = 1;
while (ch < '0' || '9' < ch) {
if (ch == '-') A = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
ret = ret*10LL + 1LL*(ch - '0');
ch = getchar();
}
return ret*A;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
//freopen("test.txt","w",stdout);
#endif
cin >> n;
scanf("%s",ch + 1);
for (int i = 1; i <= n; i++)
a[i] = getLL(),ch[i] -= ('a' - 1);
Getsa();
Rank_and_Height();
//Print();
s[top = 1] = 1;
height[1] = 0;
height[n + 1] = -1;
for (int i = 2; i <= n + 1; i++) {
while (top && height[s[top]] > height[i])
R[s[top]] = i - 1,--top;
s[++top] = i;
}
s[top = 1] = n; L[1] = 1;
for (int i = n - 1; i; i--) {
while (top && height[s[top]] >= height[i])
L[s[top]] = i + 1,--top;
s[++top] = i;
}
Pre_Work();
for (int i = 1; i <= n; i++) a2[i] = -2E18;
for (int i = 2; i <= n; i++) {
LL A = i - L[i] + 1;
LL B = R[i] - i + 1;
a1[height[i]] += A*B;
Query(L[i] - 1,i - 1,0); Query(i,R[i],1);
LL Ma = -2E18;
Ma = max(Ma,mi[0]*mi[1]);
Ma = max(Ma,ma[0]*ma[1]);
Ma = max(Ma,mi[0]*ma[1]);
Ma = max(Ma,ma[0]*mi[1]);
a2[height[i]] = max(a2[height[i]],Ma);
}
for (int i = n - 1; i >= 0; i--)
a1[i] += a1[i + 1],a2[i] = max(a2[i],a2[i+1]);
for (int i = 0; i < n; i++)
if (!a1[i]) puts("0 0");
else printf("%lld %lld\n",a1[i],a2[i]);
return 0;
}