http://www.lydsy.com/JudgeOnline/problem.php?id=4516

考虑在后面新加一个字母产生的影响

假设是第i个

如果不考虑重复,那么会增加i个不同的字符串

考虑重复的话,就是找到 最小的j,满足s[j……i] 在之前出现过,那么i的贡献就是j-1

即查找与某个串的最长公共后缀

如果把整个串倒过来,就变成了每次在前面加一个,查找最长公共前缀

这个利用后缀数组的height数组可以解决

有一个很显然的结论是:

若ijk满足  rank(i)<rank(j)<rank(k)   或者 rank(i)>rank(j)>rank(k) ,则LCP(i,j)>=LCP(i,k)

所以每次找到 排名在它前面的 第一个串,找到排名在它后面的第一个串

这个串分别与他们求LCS,取大的那个,就是加入i后的重复的串

求LCS用height数组+RMQ,

找排名在它前/后的第一个串可以用平衡树/set

网上看的题解用的树状数组

第一个树状数组 找前面的第一个串,权值=位置,这样找rk[i] 前面最大的即可

第二个树状数组 找后面的第一个串,权值=n-位置+1,就是倒着的,这样就是找n-rk[i] 前面最大的

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> using namespace std; #define N 100001 #define lowbit(x) (x&-x) int n,tot;
int a[N],has[N]; int v[N];
int sa[][N],rk[][N];
int height[N];
int p,q=; int F[N][]; int c[][N]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void mul(int k,int *sa,int *rk,int *SA,int *RK)
{
for(int i=;i<=n;++i) v[rk[sa[i]]]=i;
for(int i=n;i;--i) if(sa[i]-k>) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+;i<=n;++i) SA[v[rk[i]]--]=i;
for(int i=;i<=n;++i)
RK[SA[i]]=RK[SA[i-]]+(rk[SA[i-]+k]!=rk[SA[i]+k] || rk[SA[i-]]!=rk[SA[i]]);
} void presa()
{
memset(v,,sizeof(v));
for(int i=;i<=n;++i) v[a[i]]++;
for(int i=;i<=tot;++i) v[i]+=v[i-];
for(int i=;i<=n;++i) sa[p][v[a[i]]--]=i;
for(int i=;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-]]+(a[sa[p][i-]]!=a[sa[p][i]]);
for(int k=;k<n;k<<=,swap(p,q)) mul(k,sa[p],rk[p],sa[q],rk[q]);
} void get_height()
{
int k=,j;
for(int i=;i<=n;++i)
{
j=sa[p][rk[p][i]-];
while(i+k<=n && j+k<=n && a[i+k]==a[j+k]) k++;
height[rk[p][i]]=k;
if(k) k--;
}
} int change(int w,int r)
{
for(int i=r;i<=n;i+=lowbit(i)) c[w][i]=max(c[w][i],r);
} int ask(int w,int r)
{
int ans=;
for(int i=r;i;i-=lowbit(i)) ans=max(ans,c[w][i]);
return ans;
} int rmq(int l,int r)
{
int k=log2(r-l+);
return min(F[l][k],F[r-(<<k)+][k]);
} void solve()
{
for(int i=;i<=n;++i) F[i][]=height[i];
for(int j=,k=;k<n;++j,k<<=)
for(int i=;i+(k<<)-<=n;++i)
F[i][j]=min(F[i][j-],F[i+k][j-]);
int pos;
int pre,suc,lcs;
long long ans=;
for(int i=n;i;--i)
{
pos=rk[p][i];
pre=ask(,pos-); suc=n-ask(,n-pos)+;
lcs=;
if(pre>=) lcs=max(lcs,rmq(pre+,pos));
if(suc<=n) lcs=max(lcs,rmq(pos+,suc));
ans+=n-i+-lcs;
cout<<ans<<'\n';
change(,pos); change(,n-pos+);
}
} int main()
{
read(n);
for(int i=n;i;--i) read(a[i]),has[i]=a[i];
sort(has+,has+n+);
tot=unique(has+,has+n+)-has-;
for(int i=;i<=n;++i) a[i]=lower_bound(has+,has+tot+,a[i])-has;
presa();
get_height();
solve();
fclose(stdin); fclose(stdout);
return ;
}

bzoj千题计划283:bzoj4516: [Sdoi2016]生成魔咒(后缀数组)的更多相关文章

  1. BZOJ4516: [Sdoi2016]生成魔咒(后缀数组 set RMQ)

    题意 题目链接 Sol 毒瘤SDOI 终于有一道我会做的题啦qwq 首先,本质不同的子串的个数 $ = \frac{n(n + 1)}{2} - \sum height[i]$ 把原串翻转过来,每次就 ...

  2. BZOJ4516: [Sdoi2016]生成魔咒 后缀自动机

    #include<iostream> #include<cstdio> #include<cstring> #include<queue> #inclu ...

  3. [SDOI2016] 生成魔咒 - 后缀数组,平衡树,STL,时间倒流

    [SDOI2016] 生成魔咒 Description 初态串为空,每次在末尾追加一个字符,动态维护本质不同的子串数. Solution 考虑时间倒流,并将串反转,则变为每次从开头删掉一个字符,即每次 ...

  4. 【bzoj4516】[Sdoi2016]生成魔咒 后缀数组+倍增RMQ+STL-set

    题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2].一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1,2 ...

  5. [bzoj4516][Sdoi2016]生成魔咒——后缀自动机

    Brief Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生 ...

  6. bzoj千题计划314:bzoj3238: [Ahoi2013]差异(后缀数组+st表+单调栈)

    https://www.lydsy.com/JudgeOnline/problem.php?id=3238 跟 bzoj3879 差不多 #include<cstdio> #include ...

  7. BZOJ.4516.[SDOI2016]生成魔咒(后缀数组 RMQ)

    题目链接 后缀自动机做法见这(超好写啊). 后缀数组是可以做的: 本质不同的字符串的个数为 \(子串个数-\sum_{ht[i]}\),即 \(\frac{n(n+1)}{2}-\sum_{ht[i] ...

  8. BZOJ 4516: [Sdoi2016]生成魔咒——后缀数组、并查集

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4516 题意 一开始串为空,每次往串后面加一个字符,求本质不同的子串的个数,可以离线.即长度为 ...

  9. BZOJ 4516: [Sdoi2016]生成魔咒(后缀数组)

    传送门 解题思路 题目其实就是动态维护本质不同的串的个数.考虑到只有加数字的操作,所以可以用后缀数组.题目是每次往后加数字,这样不好处理,因为每次加数字之后所有的后缀都会改变.所以要转化一下思路,就是 ...

  10. BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]

    4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...

随机推荐

  1. identityServer4 中的概念(Scope,claim)

    在IdentityServer中好多地方出现这几个词,这单词的解释也有好多大神解释过: chaim: ASP.NET Core 之 Identity 入门(一),这个是asp.net identity ...

  2. Js_特效II

    字号缩放 让文字大点,让更多的用户看的更清楚.(也可以把字体变为百分比来实现)<script type="text/javascript">  function doZ ...

  3. SSM整合配置(Spring+Spring MVC+Mybatis)

    一.配置准备   通过Maven工程,在eclipse中整合SSM,并在Tomcat服务器上运行 在进行配置前,先理清楚要配置哪些文件,如图,除web.xml外,其余三个配置文件名称均可自定义: 如图 ...

  4. GitLab篇之Linux下环境搭建

    之前公司一直在使用微软的VSS和SVN做为源代码管理工具,考虑到VSS和SVN的局限性,个人一直建议我们应该采用Git来管理我们的源代码.Git的好处不多说相信大家也都知道的.Git不仅仅是一个源代码 ...

  5. OpenGL学习(3)——Shader

    之前已经接触过Vertex Shader和Fragment Shader,这次学习如何编写Shader并封装成类. Shader源码主要有四部分: 版本声明 #version xxx core: 使用 ...

  6. Test Cases

    对于mode1 1 路径下一个空文件夹       结果:生成一个空的txt 2路径下一个文件夹内包含一个txt内容为abd(最基本的一个单词) 3路径下一个空文件夹一个txt,txt内容为以不同符号 ...

  7. 《Linux内核分析》第二周学习小结 操作系统是如何工作的?

    郝智宇   无转载   <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.函数调用堆栈: 1.计算机是 ...

  8. [JSP] c:forEach 如何输出序号

    关键在于<c:forEach>的varStatus属性,具体代码如下: <table width="500" border="0" cells ...

  9. ElasticSearch 5.6.1 安装 Kibana、X-Pack和head

    前面已经有写过ElasticSearch和iK的安装了这里就不在所了. 安装Kiabna 在下载tar包的时候需要注意下一安装的es版本号,按照官网的说明版本是对应一致的. https://www.e ...

  10. Software-Defined Networking:A Comprehensive Survey--Day1

    Software-Defined Networking:A Comprehensive Survey 摘要: 传统网络复杂且难以管理,根据预定义策咯也难以对网络进行配置,也难以重新配置. 软件定义网络 ...