[BZOJ4199][NOI2015]品酒大会(后缀数组+单调栈+ST表)
来源:互联网 发布:顺丰机打运单软件 编辑:程序博客网 时间:2024/05/17 22:53
=== ===
这里放传送门
=== ===
题解
这题好多网上的标算写的都是并查集。。然而ATP当时做的时候一看这不就是求LCP吗求LCP不光用单调栈吗然后就开始想单调栈最后还真想出来了一个科学的做法。。不过就是有点儿慢。。。
首先如果我们可以求出所有LCP恰好是i的后缀的答案,那么我们就可以用
在做单调栈的时候每次加入一个后缀
考虑暴力一点的做法,我们可以在每次加入一个后缀以后都扫描整个单调栈,设这一段跟
那么如何优化呢?可以发现比较靠近栈底的那些“段”是会保留在栈内很长时间的,也就是它会被累加好几次。那么只要知道它待在栈内的时间新加入了多少个后缀,就能知道它会被累加多少遍。对每一段维护一个入栈出栈时间戳就可以了。对于第二问要维护每一段内的最大最小值,然后因为它待在栈里的时间内加入的后缀是一段连续的区间,所以可以用ST表查出这一段后缀的最大最小值用来更新答案。
这样做的话时间复杂度和空间复杂度都是
代码
#include<cstdio>#include<cstring>#include<algorithm>#define Pow 19using namespace std;const long long inf=2e18;int n,len,a[300010],top,st[300010],cnt[300010],m,p,b[300010],SA[300010],rank[300010],L[300010],now;int height[300010],*x,*y,Xx[300010],Yy[300010];char s[300010];long long f[300010],Maxp[300010],Minn[300010],Max[300010];namespace STtable{ int Max[300010][22],Min[300010][22],lg[300010]; void build(){ for (int i=1,p=0;i<=n;i++){ while ((1<<p)<=i) ++p; lg[i]=p-1; } for (int i=0;i<n;i++) Min[i][0]=Max[i][0]=a[SA[i]]; for (int i=1;i<=Pow;i++) for (int j=0;j<n;j++){ int pos=j+(1<<(i-1)); if (pos>=n) break; Min[j][i]=min(Min[j][i-1],Min[pos][i-1]); Max[j][i]=max(Max[j][i-1],Max[pos][i-1]); } } long long getMax(int l,int r){ int j=lg[r-l+1]; return max(Max[l][j],Max[r-(1<<j)+1][j]); } long long getMin(int l,int r){ int j=lg[r-l+1]; return min(Min[l][j],Min[r-(1<<j)+1][j]); }}bool cmp(int i,int j,int l){ return y[i]==y[j]&&((i+l>=len)?-1:y[i+l])==((j+l>=len)?-1:y[j+l]);}void get_SA(){ m=200;x=Xx;y=Yy; for (int i=0;i<len;i++) ++b[x[i]=s[i]]; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=len-1;i>=0;i--) SA[--b[x[i]]]=i; for (int k=1;k<=len;k<<=1){ p=0; for (int i=len-k;i<len;i++) y[p++]=i; for (int i=0;i<len;i++) if (SA[i]>=k) y[p++]=SA[i]-k; for (int i=0;i<=m;i++) b[i]=0; for (int i=0;i<len;i++) ++b[x[y[i]]]; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=len-1;i>=0;i--) SA[--b[x[y[i]]]]=y[i]; swap(x,y);p=1;x[SA[0]]=0; for (int i=1;i<len;i++) x[SA[i]]=cmp(SA[i-1],SA[i],k)?p-1:p++; if (p>len) break;m=p; } p=0; for (int i=0;i<len;i++) rank[SA[i]]=i; for (int i=0;i<len;i++){ if (rank[i]==0) continue; int j=SA[rank[i]-1]; while (i+p<len&&j+p<len&&s[i+p]==s[j+p]) ++p; height[rank[i]]=p; if (p!=0) p--; }}void Add(int i,long long val){ Minn[i]=min(Minn[i],val); Maxp[i]=max(Maxp[i],val);}void calc(int i){ int len=i-L[i],c=now-cnt[i]; long long Maxnow,Minnow; f[height[i]]+=(long long)len*c; Maxnow=STtable::getMax(cnt[i]+1,now); Minnow=STtable::getMin(cnt[i]+1,now); Max[height[i]]=max(Max[height[i]],Maxnow*Maxp[i]); Max[height[i]]=max(Max[height[i]],Minnow*Minn[i]);}int main(){ scanf("%d",&n); for (int i=0;i<n;i++){ char c=getchar(); while (c<'a'||c>'z') c=getchar(); s[i]=c; } for (int i=0;i<n;i++) scanf("%d",&a[i]); len=n;get_SA(); STtable::build(); for (int i=0;i<=n;i++) Max[i]=Maxp[i]=-inf; for (int i=0;i<=n;i++) Minn[i]=inf; for (int i=1;i<len;i++){ L[i]=i-1; Add(i,a[SA[i-1]]); while (top!=0&&height[st[top]]>=height[i]){ calc(st[top]);L[i]=L[st[top]]; Add(i,Maxp[st[top]]); Add(i,Minn[st[top]]); --top; } st[++top]=i;cnt[i]=now;++now; } while (top!=0){calc(st[top]);--top;} for (int i=len-1;i>=0;i--){ Max[i]=max(Max[i],Max[i+1]); f[i]=f[i]+f[i+1]; } for (int i=0;i<len;i++) if (Max[i]==-inf) Max[i]=0; for (int i=0;i<len;i++) printf("%I64d %I64d\n",f[i],Max[i]); return 0;}
偏偏在最后出现的补充说明
理解后缀数组的常用套路
0 0
- [BZOJ4199][NOI2015]品酒大会(后缀数组+单调栈+ST表)
- [BZOJ4199][NOI2015]品酒大会 后缀数组
- [BZOJ4199][NOI2015]品酒大会-后缀数组
- [BZOJ4199][Noi2015]品酒大会(后缀数组+并查集)
- bzoj4199 [Noi2015]品酒大会 后缀数组+并查集
- 【bzoj4199】[Noi2015]品酒大会 后缀自动机
- bzoj4199[luoguP2178]品酒大会[noi2015] (后缀数组+并查集)
- 【NOI2015】【BZOJ4199】品酒大会
- [BZOJ4199][Noi2015]品酒大会
- [BZOJ4199] [Noi2015]品酒大会
- [bzoj4199][NOI2015]品酒大会
- BZOJ4199 [Noi2015]品酒大会
- NOI2015.品酒大会(后缀数组)
- NOI2015品酒大会 后缀数组
- bzoj4199&uoj131: [Noi2015]品酒大会
- BZOJ4199 NOI2015 品酒大会 题解&代码
- 【NOI2015】bzoj4199 品酒大会【解法一】
- 【NOI2015】bzoj4199 品酒大会【解法二】
- sql server附加数据库出错
- 时钟电路-负载电容和电阻计算
- Vim插件之vim-surround
- dos窗口中虚拟机的IP可以ping通,ping主机名不能ping通
- 【图论入门】城市平乱
- [BZOJ4199][NOI2015]品酒大会(后缀数组+单调栈+ST表)
- LoadRunner中的 并发用户与集合点设置的关系
- 作家、文学大家、大师的艺术风格
- 文章标题
- 图解正向代理、反向代理、透明代理
- TCP 11种状态
- 蓝桥杯第五届省赛(热身)
- debain 截图工具 实用的
- 发送一个消息到邮箱中,OSMboxPost()