zoukankan      html  css  js  c++  java
  • BZOJ 4199 [Noi2015]品酒大会:后缀数组 + 并查集

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4199

    题意:

      给你一个长度为n的字符串s,和一个长为n的数组v。

      对于每个整数r∈[0,n-1]:

        (1)问你有多少对后缀(suffix(i), suffix(j)),满足LCP(suffix(i), suffix(j)) >= r

        (2)输出mul[r] = max(v[i]*v[j]),其中i,j满足(1)的条件

    题解:

      先考虑第(1)问。

      由于LCP只受连续的一段height中最小值的影响

      所以先将height数组排序,然后按height从大到小的顺序,合并当前height对应的两个后缀suffix(i)和suffix(j)所在的集合。

      那么对于任意两个分别属于这两个集合的后缀来说,它们的LCP一定为当前height。

      假设ans[r]表示LCP恰好为r的后缀对个数,那么此时的贡献为ans[height] += siz[find(i)] * siz[find(j)]

      最后对ans数组求一遍后缀和,即为LCP >= r的后缀对个数。

      然后再考虑第(2)问。

      由于v[i]有可能为负值,所以对于每个集合,维护集合中元素对应v[i]的最大值和最小值。

      那么每次合并时,用max(两个集合的最大值之积,最小值之积)更新mul[par]即可。

    AC Code:

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <algorithm>
      5 #define MAX_N 300005
      6 
      7 using namespace std;
      8 
      9 struct Height
     10 {
     11     int v,id;
     12     Height(int _v,int _id)
     13     {
     14         v=_v; id=_id;
     15     }
     16     Height(){}
     17     friend bool operator < (const Height &a,const Height &b)
     18     {
     19         return a.v<b.v;
     20     }
     21 };
     22 
     23 int n;
     24 int a[MAX_N];
     25 int sa[MAX_N];
     26 int rk[MAX_N];
     27 int t1[MAX_N];
     28 int t2[MAX_N];
     29 int cnt[MAX_N];
     30 int tsa[MAX_N];
     31 int height[MAX_N];
     32 int par[MAX_N];
     33 long long siz[MAX_N];
     34 long long maxn[MAX_N];
     35 long long minn[MAX_N];
     36 long long v[MAX_N];
     37 long long ans[MAX_N];
     38 long long mul[MAX_N];
     39 char s[MAX_N];
     40 Height h[MAX_N];
     41 
     42 void rsort()
     43 {
     44     memset(cnt,0,sizeof(cnt));
     45     for(int i=1;i<=n;i++) cnt[t2[i]]++;
     46     for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
     47     for(int i=n;i>=1;i--) tsa[cnt[t2[i]]--]=i;
     48     memset(cnt,0,sizeof(cnt));
     49     for(int i=1;i<=n;i++) cnt[t1[i]]++;
     50     for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
     51     for(int i=n;i>=1;i--) sa[cnt[t1[tsa[i]]]--]=tsa[i];
     52 }
     53 
     54 void suffix()
     55 {
     56     memset(cnt,0,sizeof(cnt));
     57     for(int i=1;i<=n;i++) a[i]=s[i],cnt[a[i]]++;
     58     for(int i='a';i<='z';i++) cnt[i]+=cnt[i-1];
     59     for(int i=1;i<=n;i++) rk[i]=cnt[a[i]];
     60     int len=1;
     61     while(len<n)
     62     {
     63         for(int i=1;i<=n;i++)
     64         {
     65             t1[i]=rk[i];
     66             t2[i]=i+len<=n ? rk[i+len] : 0;
     67         }
     68         rsort();
     69         for(int i=1;i<=n;i++)
     70         {
     71             rk[sa[i]]=rk[sa[i-1]]+(t1[sa[i]]!=t1[sa[i-1]] || t2[sa[i]]!=t2[sa[i-1]]);
     72         }
     73         len<<=1;
     74     }
     75     int k=0;
     76     for(int i=1;i<=n;i++)
     77     {
     78         k=k?k-1:k;
     79         int j=sa[rk[i]-1];
     80         while(a[i+k]==a[j+k]) k++;
     81         height[rk[i]]=k;
     82     }
     83 }
     84 
     85 void init_union_find()
     86 {
     87     for(int i=1;i<=n;i++)
     88     {
     89         par[i]=i;
     90         siz[i]=1;
     91         maxn[i]=minn[i]=v[i];
     92     }
     93 }
     94 
     95 int find(int x)
     96 {
     97     return par[x]==x ? x : par[x]=find(par[x]);
     98 }
     99 
    100 void unite(int x,int y,int r)
    101 {
    102     int px=find(x);
    103     int py=find(y);
    104     ans[r]+=siz[px]*siz[py];
    105     mul[r]=max(mul[r],max(maxn[px]*maxn[py],minn[px]*minn[py]));
    106     siz[py]+=siz[px];
    107     maxn[py]=max(maxn[py],maxn[px]);
    108     minn[py]=min(minn[py],minn[px]);
    109     par[px]=py;
    110 }
    111 
    112 void read()
    113 {
    114     scanf("%d%s",&n,s+1);
    115     for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
    116 }
    117 
    118 void work()
    119 {
    120     suffix();
    121     init_union_find();
    122     for(int i=2;i<=n;i++) h[i]=Height(height[i],i);
    123     sort(h+2,h+1+n);
    124     memset(ans,0,sizeof(ans));
    125     memset(mul,0x80,sizeof(mul));
    126     for(int i=n;i>=2;i--) unite(sa[h[i].id],sa[h[i].id-1],h[i].v);
    127     for(int i=n-1;i>=0;i--) ans[i]+=ans[i+1],mul[i]=max(mul[i],mul[i+1]);
    128     for(int i=0;i<n;i++)
    129     {
    130         if(ans[i]) printf("%lld %lld
    ",ans[i],mul[i]);
    131         else printf("0 0
    ");
    132     }
    133 }
    134 
    135 int main()
    136 {
    137     read();
    138     work();
    139 }
  • 相关阅读:
    shh登入不能自动执行.bashrc
    Markdown 公式指导手册
    机器学习(ML)十六之目标检测基础
    机器学习(ML)十五之梯度下降和随机梯度下降
    机器学习(ML)十四之凸优化
    机器学习(ML)十三之批量归一化、RESNET、Densenet
    机器学习(ML)十二之编码解码器、束搜索与注意力机制
    机器学习(ML)十一之CNN各种模型
    机器学习(ML)十之CNN
    机器学习(ML)九之GRU、LSTM、深度神经网络、双向循环神经网络
  • 原文地址:https://www.cnblogs.com/Leohh/p/8447308.html
Copyright © 2011-2022 走看看