Files
SH-Quizzes/ACMOJ-2037.cpp
2023-12-23 22:23:48 +08:00

338 lines
8.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <algorithm>
#include <cstdio>
#include <cstring>
#define unlikely(x) __builtin_expect(!!(x), 0)
struct char_reader {
FILE *f;
char *buf, *p1, *p2;
int size;
char_reader(FILE *fin, int bufsize = 1 << 16) {
f = fin;
size = bufsize;
p1 = p2 = 0;
buf = new char[size];
}
~char_reader() { delete[] buf; }
inline int operator()() {
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, size, f), p1 == p2)
? EOF
: *p1++;
}
};
struct char_writer {
FILE *f;
char *buf, *p, *end;
int size;
char_writer(FILE *fout, int bufsize = 1 << 16) {
f = fout;
size = bufsize;
buf = new char[size];
p = buf;
end = buf + bufsize;
}
~char_writer() {
fwrite(buf, p - buf, 1, f);
delete[] buf;
}
inline char operator()(char ch) {
if (unlikely(end == p)) {
fwrite(buf, end - buf, 1, f);
p = buf;
}
return *p++ = ch;
}
};
char_reader gch(stdin);
char_writer wch(stdout);
template <typename T>
inline int read(T &t) {
bool f = false;
int ch;
while (ch = gch(), !((ch >= '0' && ch <= '9') || ch == '-')) {
if (ch == EOF) return 0;
}
t = 0;
if (ch == '-') f = true, ch = gch();
t = ch ^ 48;
while (ch = gch(), ch >= '0' && ch <= '9')
t = (t << 3) + (t << 1) + (ch ^ 48);
if (f) t = -t;
return 1;
}
inline int read(char &c) {
c = 0;
int ch;
while (ch = gch(), (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) {
if (ch == EOF) return 0;
}
c = ch;
return 1;
}
inline int read(char *s) {
int ch;
while (ch = gch(), (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) {
if (ch == EOF) return 0;
}
*s++ = ch;
while (ch = gch(),
!(ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t') && ch != EOF)
*s++ = ch;
*s++ = 0;
return 1;
}
inline int read(const char *s) { return read((char *)s); }
inline int readline(char *s) {
int ch;
while (ch = gch(), (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) {
if (ch == EOF) return 0;
}
*s++ = ch;
while (ch = gch(), !(ch == '\n' || ch == '\r') && ch != EOF) *s++ = ch;
*s++ = 0;
return 1;
}
inline int readline(const char *s) { return readline((char *)s); }
template <typename T>
inline void write(T t) {
int stk[20], cnt = 0;
if (t == 0) {
wch('0');
return;
}
if (t < 0) {
wch('-');
t = -t;
}
while (t > 0) {
stk[cnt++] = t % 10;
t /= 10;
}
while (cnt) wch(stk[--cnt] + '0');
}
inline void write(char t) { wch(t); }
inline void write(char *s) {
while (*s) wch(*s++);
}
inline void write(const char *s) { write((char *)s); }
#if __cplusplus >= 201103L
template <typename T, typename... Args>
inline int read(T &t, Args &...args) {
return read(t) + read(args...);
}
template <typename T, typename... Args>
inline void write(T t, Args... args) {
write(t);
write(args...);
}
#else
template <typename A_t, typename B_t>
inline int read(A_t &a, B_t &b) {
return read(a) + read(b);
}
template <typename A_t, typename B_t, typename C_t>
inline int read(A_t &a, B_t &b, C_t &c) {
return read(a) + read(b) + read(c);
}
template <typename A_t, typename B_t, typename C_t, typename D_t>
inline int read(A_t &a, B_t &b, C_t &c, D_t &d) {
return read(a) + read(b) + read(c) + read(d);
}
template <typename A_t, typename B_t>
inline void write(A_t a, B_t b) {
write(a);
write(b);
}
template <typename A_t, typename B_t, typename C_t>
inline void write(A_t a, B_t b, C_t c) {
write(a);
write(b);
write(c);
}
template <typename A_t, typename B_t, typename C_t, typename D_t>
inline void write(A_t a, B_t b, C_t c, D_t d) {
write(a);
write(b);
write(c);
write(d);
}
#endif
using namespace std;
typedef long long LL;
const int kMaxN = 3e5 + 10;
const LL kInf = 1e18 + 10;
int n;
char s[kMaxN];
int sa[kMaxN * 2], rk[kMaxN * 2], height[kMaxN];
LL a[kMaxN];
namespace __SA_IS {
int str[kMaxN * 2], sa[kMaxN * 2], typ[kMaxN * 2], c[kMaxN], p[kMaxN * 2],
sbuc[kMaxN], lbuc[kMaxN], name[kMaxN];
inline int islms(int *typ, int i) { return !typ[i] && (i == 1 || typ[i - 1]); }
int cmp(int *s, int *typ, int p, int q) {
do {
if (s[p] != s[q]) return 1;
p++;
q++;
} while (!islms(typ, p) && !islms(typ, q));
return (!islms(typ, p) || !islms(typ, q) || s[p] != s[q]);
}
void isort(int *s, int *sa, int *typ, int *c, int n, int m) {
int i;
for (lbuc[0] = sbuc[0] = c[0], i = 1; i <= m; i++) {
lbuc[i] = c[i - 1] + 1;
sbuc[i] = c[i];
}
for (i = 1; i <= n; i++)
if (sa[i] > 1 && typ[sa[i] - 1]) sa[lbuc[s[sa[i] - 1]]++] = sa[i] - 1;
for (i = n; i >= 1; i--)
if (sa[i] > 1 && !typ[sa[i] - 1]) sa[sbuc[s[sa[i] - 1]]--] = sa[i] - 1;
}
void build_sa(int *s, int *sa, int *typ, int *c, int *p, int n, int m) {
int i;
for (i = 0; i <= m; i++) c[i] = 0;
for (i = 1; i <= n; i++) c[s[i]]++;
for (i = 1; i <= m; i++) c[i] += c[i - 1];
typ[n] = 0;
for (i = n - 1; i >= 1; i--)
if (s[i] < s[i + 1])
typ[i] = 0;
else if (s[i] > s[i + 1])
typ[i] = 1;
else
typ[i] = typ[i + 1];
int cnt = 0;
for (i = 1; i <= n; i++)
if (!typ[i] && (i == 1 || typ[i - 1])) p[++cnt] = i;
for (i = 1; i <= n; i++) sa[i] = 0;
for (i = 0; i <= m; i++) sbuc[i] = c[i];
for (i = 1; i <= cnt; i++) sa[sbuc[s[p[i]]]--] = p[i];
isort(s, sa, typ, c, n, m);
int last = 0, t = -1, x;
for (i = 1; i <= n; i++) {
x = sa[i];
if (!typ[x] && (x == 1 || typ[x - 1])) {
if (!last || cmp(s, typ, x, last))
name[x] = ++t;
else
name[x] = t;
last = x;
}
}
for (i = 1; i <= cnt; i++) s[n + i] = name[p[i]];
if (t < cnt - 1)
build_sa(s + n, sa + n, typ + n, c + m + 1, p + n, cnt, t);
else
for (i = 1; i <= cnt; i++) sa[n + s[n + i] + 1] = i;
for (i = 0; i <= m; i++) sbuc[i] = c[i];
for (i = 1; i <= n; i++) sa[i] = 0;
for (i = cnt; i >= 1; i--) sa[sbuc[s[p[sa[n + i]]]]--] = p[sa[n + i]];
isort(s, sa, typ, c, n, m);
}
} // namespace __SA_IS
void SA_IS(char *s, int n, int *sa, int *rk) {
using namespace __SA_IS;
for (int i = 1; i <= n; i++) str[i] = s[i];
str[++n] = 0;
build_sa(str, sa, typ, c, p, n, 256);
n--;
for (int i = 1; i <= n; i++) sa[i] = sa[i + 1];
for (int i = 1; i <= n; i++) rk[sa[i]] = i;
}
void computeHeight(char *s, int n, int *sa, int *rk, int *height) {
int k = 0;
for (int i = 1; i <= n; i++) {
if (rk[i] == 1) {
height[rk[i]] = 0;
continue;
}
if (k > 0) {
k--;
}
int j = sa[rk[i] - 1];
while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) {
k++;
}
height[rk[i]] = k;
}
}
LL exact_method[kMaxN], exact_yammy[kMaxN];
struct H_Struct {
int height_index, height_value;
H_Struct() {}
H_Struct(int __h_i, int __h_v) : height_index(__h_i), height_value(__h_v) {}
};
bool operator<(const H_Struct &A, const H_Struct &B) {
return A.height_value > B.height_value;
}
H_Struct merge_pair[kMaxN];
int fa[kMaxN], min_a[kMaxN], max_a[kMaxN], subtree_size[kMaxN];
LL subtree_max_yammy[kMaxN];
inline int ff(int u) {
int v = u, x;
while (u != fa[u]) u = fa[u];
while (v != u) {
x = fa[v];
fa[v] = u;
v = x;
}
return u;
}
int main() {
#ifdef local
freopen("pro.in", "r", stdin);
#endif
read(n);
read(s + 1);
for (int i = 1; i <= n; i++) read(a[i]);
SA_IS(s, n, sa, rk);
computeHeight(s, n, sa, rk, height);
for (int i = 2; i <= n; i++) merge_pair[i - 1] = H_Struct(i, height[i]);
sort(merge_pair + 1, merge_pair + 1 + n - 1);
for (int i = 1; i <= n; i++) {
fa[i] = i;
max_a[i] = min_a[i] = a[i];
subtree_size[i] = 1;
subtree_max_yammy[i] = -kInf;
exact_yammy[i] = -kInf;
}
for (int i = 1; i <= n - 1; i++) {
int x = sa[merge_pair[i].height_index];
int y = sa[merge_pair[i].height_index - 1];
int ht = merge_pair[i].height_value;
// printf("%d and %d\n", x, y);
x = ff(x);
y = ff(y);
fa[y] = x;
exact_method[ht] += (LL)subtree_size[x] * (LL)subtree_size[y];
// 可以归纳证明当多个height相同时这个递推方式也是正确的
subtree_size[x] += subtree_size[y];
subtree_max_yammy[x] = max(subtree_max_yammy[x], subtree_max_yammy[y]);
// printf("smy %d %lld\n", x, subtree_max_yammy[x]);
subtree_max_yammy[x] =
max(subtree_max_yammy[x],
max(min_a[x] * (LL)min_a[y], max_a[x] * (LL)max_a[y]));
// printf("smy %d %lld\n", x, subtree_max_yammy[x]);
subtree_max_yammy[x] =
max(subtree_max_yammy[x],
max(max_a[x] * (LL)min_a[y], min_a[x] * (LL)max_a[y]));
// printf("smy %d %lld\n", x, subtree_max_yammy[x]);
min_a[x] = min(min_a[x], min_a[y]);
max_a[x] = max(max_a[x], max_a[y]);
// printf("mm %d %d\n", x, max_a[x]);
// printf("mi %d %d\n", x, min_a[x]);
exact_yammy[ht] = max(exact_yammy[ht], subtree_max_yammy[x]);
// 这里很显然
}
for (int i = n - 2; i >= 0; i--) {
exact_method[i] += exact_method[i + 1];
exact_yammy[i] = max(exact_yammy[i], exact_yammy[i + 1]);
}
for (int i = 0; i <= n - 1; i++)
printf("%lld %lld\n", exact_method[i],
exact_method[i] != 0 ? exact_yammy[i] : 0);
return 0;
}