品酒大会 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 }
posted @ 2017-02-21 17:35  草根柴鸡  阅读(144)  评论(0编辑  收藏  举报