zoukankan      html  css  js  c++  java
  • 品酒大会 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
    ", ans_si[i], ans_si[i] ? ans_mx[i] : 0);
    115 }
  • 相关阅读:
    实验3
    实验2
    实验1
    阿里云服务器搭建Halo博客系统
    移动开发技术(三)
    在服务器上部署Anki-Server
    软件测试技术(二)
    函数相关定理
    移动开发技术(一)
    高等数学函数求导
  • 原文地址:https://www.cnblogs.com/lytccc/p/6425301.html
Copyright © 2011-2022 走看看