BZOJ4516: [Sdoi2016]生成魔咒(后缀数组)
来源:互联网 发布:供应商主数据 编辑:程序博客网 时间:2024/05/17 07:18
传送门
给一个串,分别求[1,r] , r=1,2,3,4….,n的不同子串个数。
题解:后缀数组
先把串反转,其实就是求每一个后缀的不同子串个数。依次从后往前加入后缀,一个后缀能产生的不同子串个数为这个后缀的长度减去与它的排名前一名的后缀的长度,维护前缀即可。
每次插入一个后缀t,设它排名前一个后缀为p,后一个后缀为s。因为之前插入s或t后缀时必然会减去最长公共前缀,因此,答案先加上lcp(p,s)。再减去lcp(t,p),lcp(t,s)。求出height数组后rmp用st表预处理,查询时间复杂度O(1)。
对于前后缀的维护,用树状数组。总的时间复杂度
#include<bits/stdc++.h>using namespace std;typedef pair<int,int> pii;const int Maxn=1e5+50,INF=0x3f3f3f3f;inline int read(){ char ch=getchar();int i=0,f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();} return i*f;}int n,m,a[Maxn],tot,t1[Maxn],t2[Maxn],*rk=t1,*sa2=t2,sa[Maxn],h[Maxn],c[Maxn],mn[Maxn][30],Log[Maxn],Pow[30],pre[Maxn],suf[Maxn];pii b[Maxn];inline void Rsort(){ for(int i=1;i<=m;i++)c[i]=0; for(int i=1;i<=n;i++)c[rk[i]]++; for(int i=1;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i>=1;i--)sa[c[rk[sa2[i]]]--]=sa2[i];}inline void getsa(){ for(int i=1;i<=n;i++)rk[i]=a[i],sa2[i]=i; m=tot;Rsort(); for(int w=1,p=0;p<n;m=p,w<<=1) { p=0; for(int i=n-w+1;i<=n;i++)sa2[++p]=i; for(int i=1;i<=n;i++)if(sa[i]>w)sa2[++p]=sa[i]-w; Rsort();swap(rk,sa2);rk[sa[1]]=p=1; for(int i=2;i<=n;i++)rk[sa[i]]=(sa2[sa[i]]!=sa2[sa[i-1]]||sa2[sa[i]+w]!=sa2[sa[i-1]+w])?(++p):p; } for(int i=1,k=0,j;i<=n;h[rk[i++]]=k) for(k?k--:k,j=sa[rk[i]-1];a[i+k]==a[j+k];k++);}inline void getst(){ Pow[0]=1;Log[1]=0; for(int i=1;i<=26;i++)Pow[i]=Pow[i-1]<<1; for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1; for(int i=1;i<=n;i++)mn[i][0]=h[i]; for(int i=1;i<=26&&Pow[i]<=n;i++) for(int j=1;j+Pow[i]<=n+1;j++) mn[j][i]=min(mn[j][i-1],mn[j+Pow[i-1]][i-1]);}inline int qmn(int x,int y){return min(mn[x][Log[y-x+1]],mn[y-Pow[Log[y-x+1]]+1][Log[y-x+1]]);}inline void ins(int x){ for(int t=x;t<=n;t+=(t&(-t)))pre[t]=max(pre[t],x); for(int t=x;t;t-=(t&(-t)))suf[t]=min(suf[t],x);}inline int qpre(int x){ int res=0; for(int t=x;t;t-=(t&(-t)))res=max(res,pre[t]); return res;}inline int qsuf(int x){ int res=INF; for(int t=x;t<=n;t+=(t&(-t)))res=min(res,suf[t]); return res;}int buf[80];inline void W(long long x){ while(x)buf[++buf[0]]=x%10,x/=10; while(buf[0])putchar('0'+buf[buf[0]--]);}int main(){ n=read(); for(int i=1;i<=n;i++)b[i].first=read(),b[i].second=n-i+1,suf[i]=INF; sort(b+1,b+n+1); for(int i=1;i<=n;i++)(i==1||b[i].first!=b[i-1].first)?(a[b[i].second]=++tot):(a[b[i].second]=tot); getsa(); getst(); long long ans=0; for(int i=n;i>=1;i--) { int p=qpre(rk[i]),s=qsuf(rk[i]),t=rk[i]; if(p&&s!=INF)ans+=qmn(p+1,s); if(p)ans-=qmn(p+1,t); if(s!=INF)ans-=qmn(t+1,s); ans+=(n-i+1);ins(t); printf("%lld\n",ans); }}
(printf居然比输出优化快。。)
阅读全文
1 0
- BZOJ4516: [Sdoi2016]生成魔咒(后缀数组)
- [BZOJ4516] [SDOI2016] 生成魔咒 - 后缀数组/后缀自动机
- BZOJ4516 [Sdoi2016]生成魔咒 后缀自动机/后缀数组
- 【BZOJ4516】【Sdoi2016】生成魔咒 后缀数组 线段树
- [BZOJ4516][Sdoi2016]生成魔咒(后缀数组+链表||后缀自动机)
- 【bzoj4516】[Sdoi2016]生成魔咒 后缀自动机
- 后缀自动机 【Sdoi2016】生成魔咒 bzoj4516
- BZOJ4516 [Sdoi2016]生成魔咒 后缀自动机
- Bzoj4516:[Sdoi2016]生成魔咒:哈希表+后缀自动机
- [bzoj4516][SDOI2016]生成魔咒
- BZOJ4516 [Sdoi2016]生成魔咒
- bzoj4516【SDOI2016】生成魔咒
- bzoj4516: [Sdoi2016]生成魔咒
- bzoj4516: [Sdoi2016]生成魔咒
- BZOJ4516: [Sdoi2016]生成魔咒
- 【BZOJ4516】生成魔咒,后缀数组+Splay
- 【SDOI2016】bzoj4516 生成魔咒【解法一】
- 【SDOI2016】bzoj4516 生成魔咒【解法二】
- 胡润:财富自由
- STL常用容器用法之——List
- 字典树模板
- 存储函数、控制语句、循环语句
- mysql删除末尾数据后,再插入新数据id不连续解决方案
- BZOJ4516: [Sdoi2016]生成魔咒(后缀数组)
- C++实现二维离散傅里叶变换
- Jupyter云端python开发环境的搭建
- Python笔记(八)--运算符
- 直接拿来用!最火的Android开源项目(一)
- TFTP 服务器安装与配置
- poj 2586
- React native 免连WIFI真机调试。
- 3,Qt设置应用程序图标