品酒大会 BZOJ 4199
品酒大会
【问题描述】
【输入格式】
【输出格式】
【样例输入】
10
ponoiiipoi
2 1 4 7 4 8 3 6 4 7
【样例输出】
45 56 10 56 3 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0
【数据范围】
题解:
根据题意可得"r相似”也是“r - 1相似”
那么我们只要求出了所有最大为 r 相似的对数,就可以利用后缀和求出所有r相似的个数
考虑一瓶酒与另一瓶酒如果是 r 相似的,那么与其中一瓶酒 k (k > r) 相似的酒与另一瓶酒最大也为 r 相似
所以用后缀数组求出 height 数组
然后按 height 从大到小排序
每次按顺序找出两个 height 相似的点的祖先
height 相似的对数累加上两个祖先块内的点数乘积
height 相似的最大值为两个块的最小值乘积和最大值乘积的较大值
用并查集合并,处理点的个数、最大值和最小值(美味度有负数)
最后跑一遍后缀和
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdlib>
5 #include<cstdio>
6 #include<cmath>
7 using namespace std;
8 inline void Scan(int &x)
9 {
10 char c;
11 int o = 1;
12 while((c = getchar()) < '0' || c > '9')
13 if(c == '-') o = -1;
14 x = c - '0';
15 while((c = getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
16 x *= o;
17 }
18 const int me = 1000233;
19 int n;
20 int w[me];
21 int x[me];
22 int sa[me], he[me];
23 int val[me], fat[me], nex[me];
24 int rank[me];
25 long long ans_si[me], ans_mx[me];
26 char s[me];
27 struct Union
28 {
29 long long si, mx, mi;
30 };
31 Union un[me];
32 inline void Sa()
33 {
34 int m = 255;
35 for(int i = 1; i <= n; ++i) ++w[x[i] = s[i] - 'a' + 1];
36 for(int i = 1; i <= m; ++i) w[i] += w[i - 1];
37 for(int i = n; i >= 1; --i) sa[w[x[i]]--] = i;
38 for(int k = 1; k <= n; k <<= 1)
39 {
40 int p = 0;
41 for(int i = n; i >= n - k + 1; --i) rank[++p] = i;
42 for(int i = 1; i <= n; ++i)
43 if(sa[i] > k)
44 rank[++p] = sa[i] - k;
45 for(int i = 1; i <= m; ++i) w[i] = 0;
46 for(int i = 1; i <= n; ++i) ++w[x[i]];
47 for(int i = 1; i <= m; ++i) w[i] += w[i - 1];
48 for(int i = n; i >= 1; --i) sa[w[x[rank[i]]]--] = rank[i];
49 m = 0;
50 for(int i = 1; i <= n; ++i)
51 {
52 int u = sa[i], v = sa[i - 1];
53 if(x[u] != x[v] || x[u + k] != x[v + k]) rank[u] = ++m;
54 else rank[u] = m;
55 }
56 if(n == m) break;
57 for(int i = 1; i <= n; ++i) swap(x[i], rank[i]);
58 }
59 int tot = 0;
60 int i, j;
61 for(i = 1; i <= n; i ++)
62 {
63 if (tot) tot --;
64 j = sa[rank[i] - 1];
65 while (s[j + tot] == s[i + tot]) tot ++;
66 he[rank[i]] = tot;
67 }
68 }
69 inline bool rule(const int &x, const int &y)
70 {
71 return he[x] > he[y];
72 }
73 inline int Find(const int &x)
74 {
75 return (x != fat[x]) ? fat[x] = Find(fat[x]) : x;
76 }
77 inline void Un(const int &x, const int &y)
78 {
79 un[x].si += un[y].si;
80 un[x].mx = max(un[x].mx, un[y].mx);
81 un[x].mi = min(un[x].mi, un[y].mi);
82 fat[y] = x;
83 }
84 int main()
85 {
86 Scan(n);
87 scanf("%s", s + 1);
88 for(int i = 1; i <= n; ++i)
89 {
90 Scan(val[i]);
91 nex[i] = i + 1;
92 fat[i] = i;
93 }
94 Sa();
95 for(int i = 0; i <= n; ++i)
96 ans_mx[i] = -2147483647214748364;
97 for(int i = 1; i <= n; ++i)
98 un[i] = (Union) {1, val[sa[i]], val[sa[i]]};
99 sort(nex + 1, nex + n, rule);
100 for(int i = 1; i < n; ++i)
101 {
102 int x = Find(nex[i] - 1), y = Find(nex[i]);
103 int z = he[nex[i]];
104 ans_si[z] += un[x].si * un[y].si;
105 ans_mx[z] = max(ans_mx[z], max(un[x].mi * un[y].mi, un[x].mx * un[y].mx));
106 Un(x, y);
107 }
108 for(int i = n - 1; i >= 0; --i)
109 {
110 ans_si[i] += ans_si[i + 1];
111 ans_mx[i] = max(ans_mx[i], ans_mx[i + 1]);
112 }
113 for(int i = 0; i < n; ++i)
114 printf("%lld %lld\n", ans_si[i], ans_si[i] ? ans_mx[i] : 0);
115 }