应该算是远古时期的一道题了吧,不过感觉挺经典的。

题意是给出三一个字符串s,a,b,求以a开头b结尾的本质不同的字符串数。

由于n不算大,用hash就可以搞,不过这道题是存在复杂度$O(nlogn)$的做法的。

由于要求本质不同,所以可以考虑使用后缀数组来不重复地枚举字符串。

首先用两个不同的其他字符将s,a,b拼起来求后缀数组,这样就可以知道任意两个后缀的lcp了。然后将s中所有b出现的末尾位置置1,求个后缀和suf。将s中所有后缀按名次从小到大存到一个vector里。对于s中的每个后缀,设其名次为x,a的长度为la,b的长度为lb,若$lcp(x,rnk[ia])=la$,则其对答案的贡献为$suf[sa[i]+max(lcp(x,vec[i-1]),la-1,lb-1)]$。其中la-1和lb-1是为了保证字符串长度比a和b都大,lcp(x,vec[i-1])是为了保证不重复枚举,相当于没有将s与a,b拼起来时的height[x]。特别地,当x=0时为0。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+;
char buf[N];
int s[N],sa[N],buf1[N],buf2[N],c[N],n,rnk[N],ht[N],ST[N][],Log[N],ia,ib,m,la,lb,suf[N];
void Sort(int* x,int* y,int m) {
for(int i=; i<m; ++i)c[i]=;
for(int i=; i<n; ++i)++c[x[i]];
for(int i=; i<m; ++i)c[i]+=c[i-];
for(int i=n-; i>=; --i)sa[--c[x[y[i]]]]=y[i];
}
void da(int* s,int n,int m=) {
int *x=buf1,*y=buf2;
s[n]=x[n]=y[n]=-;
for(int i=; i<n; ++i)x[i]=s[i],y[i]=i;
Sort(x,y,m);
for(int k=; k<n; k<<=) {
int p=;
for(int i=n-k; i<n; ++i)y[p++]=i;
for(int i=; i<n; ++i)if(sa[i]>=k)y[p++]=sa[i]-k;
Sort(x,y,m),p=,y[sa[]]=;
for(int i=; i<n; ++i)y[sa[i]]=x[sa[i-]]==x[sa[i]]&&x[sa[i-]+k]==x[sa[i]+k]?p-:p++;
if(p==n)break;
swap(x,y),m=p;
}
}
void getht() {
for(int i=; i<n; ++i)rnk[sa[i]]=i;
ht[]=;
for(int i=,k=; i<n; ++i) {
if(k)--k;
if(!rnk[i])continue;
for(; s[i+k]==s[sa[rnk[i]-]+k]; ++k);
ht[rnk[i]]=k;
}
}
void initST() {
for(int i=; i<n; ++i)ST[i][]=ht[i];
for(int j=; (<<j)<=n; ++j)
for(int i=; i+(<<j)-<n; ++i)
ST[i][j]=min(ST[i][j-],ST[i+(<<(j-))][j-]);
}
int lcp(int l,int r) {
if(l==r)return n-sa[l];
if(l>r)swap(l,r);
l++;
int k=Log[r-l+];
return min(ST[l][k],ST[r-(<<k)+][k]);
}
vector<int> vec;
int main() {
Log[]=-;
for(int i=; i<N; ++i)Log[i]=Log[i>>]+;
scanf("%s",buf),m=strlen(buf);
for(int i=; i<m; ++i)s[n++]=buf[i];
s[n++]='z'+,ia=n;
scanf("%s",buf),m=strlen(buf),la=m;
for(int i=; i<m; ++i)s[n++]=buf[i];
s[n++]='z'+,ib=n;
scanf("%s",buf),m=strlen(buf),lb=m;
for(int i=; i<m; ++i)s[n++]=buf[i];
s[n]=;
da(s,n),getht(),initST();
for(int i=; i<ia-; ++i)if(lcp(rnk[i],rnk[ib])==lb)suf[i+lb-]=;
for(int i=ia-; i>=; --i)suf[i]+=suf[i+];
for(int i=; i<ia-; ++i)vec.push_back(rnk[i]);
sort(vec.begin(),vec.end());
int ans=;
for(int i=; i<vec.size(); ++i) {
int x=vec[i];
if(lcp(x,rnk[ia])==la)ans+=suf[sa[x]+max(i?lcp(x,vec[i-]):,max(la-,lb-))];
}
printf("%d\n",ans);
return ;
}

CodeForces - 113B Petr# (后缀数组)的更多相关文章

  1. Liar CodeForces - 822E (dp,后缀数组)

    大意: 给定串$s,t$, 给定整数$x$, 求判断$t$是否能划分为至多$x$段, 使这些段在$s$中按顺序,不交叉的出现. 设$dp_{i,j}$表示$s$匹配到$i$位, 划分了$j$段, 匹配 ...

  2. CodeForces 113B Petr#

    题目链接:http://codeforces.com/problemset/problem/113/B 题目大意: 多组数据每组给定3个字符串T,Sbeg,Sed,求字符串T中有多少子串是以Sbeg开 ...

  3. Codeforces Good Bye 2015 D. New Year and Ancient Prophecy 后缀数组 树状数组 dp

    D. New Year and Ancient Prophecy 题目连接: http://www.codeforces.com/contest/611/problem/C Description L ...

  4. 【Codeforces 113B】Petr#

    Codeforces 113 B 题意:有一个母串\(S\)以及两个串\(S_{begin}\)和\(S_{end}\),问\(S\)中以\(S_{begin}\)为开头并且以\(S_{end}\)为 ...

  5. Codeforces 432D Prefixes and Suffixes (KMP、后缀数组)

    题目链接: https://codeforces.com/contest/432/problem/D 题解: 做法一: KMP 显然next树上\(n\)的所有祖先都是答案,出现次数为next树子树大 ...

  6. Codeforces 1063F - String Journey(后缀数组+线段树+dp)

    Codeforces 题面传送门 & 洛谷题面传送门 神仙题,做了我整整 2.5h,写篇题解纪念下逝去的中午 后排膜拜 1 年前就独立切掉此题的 ymx,我在 2021 年的第 5270 个小 ...

  7. Codeforces Round #246 (Div. 2) D. Prefixes and Suffixes(后缀数组orKMP)

    D. Prefixes and Suffixes time limit per test 1 second memory limit per test 256 megabytes input stan ...

  8. Codeforces #123D: 后缀数组+单调栈

    D. String     You are given a string s. Each pair of numbers l and r that fulfill the condition 1 ≤  ...

  9. Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)

    这题做得比较复杂..应该有更好的做法 题目大意: 有一个括号序列,可以对其进行两种操作: ·        向里面加一个括号,可以在开头,在结尾,在两个括号之间加. ·        对当前括号序列进 ...

随机推荐

  1. C#开发者必须知道的13件事情

    1.开发流程 程序的Bug与瑕疵往往出现于开发流程当中.只要对工具善加利用,就有助于在你发布程序之前便将问题发现,或避开这些问题. 标准化代码书写 标准化代码书写可以使代码更加易于维护,尤其是在代码由 ...

  2. 第8课.第一个ARM裸板程序(点亮led)及申引

    1.原理图 2.芯片手册 3.几条汇编代码 1.ldr:读内存 ldr R0, [R1] 假设R1的值是x,读取地址x上的数据(4字节),保存到R0中 ldr R0, =0x12345678 (4字节 ...

  3. POJ 1734:Sightseeing trip

    Sightseeing trip Time Limit: 1000MS Memory Limit: 65536K Total Submissions: Accepted: Special Judge ...

  4. CentOS 7系统KVM虚拟机安装过程详解

    什么是 KVM ? KVM 在标准的 Linux 内核中增加了虚拟技术,从而我们可以通过优化的内核来使用虚拟技术.在 KVM 模型中,每一个虚拟机都是一个由 Linux 调度程序管理的标准进程,你可以 ...

  5. 《深入理解计算机系统》☞hello world背后的故事

    一步到位的hello world 首先一个简单的C语言版本的hello world例子,保存在文件hello.c中. #include <stdio.h> int main() { pri ...

  6. 斐波那契数列Fibonacci问题—动态规划

    斐波那契数列定义 Fibonacci array:1,1,2,3,5,8,13,21,34,... 在数学上,斐波那契数列是以递归的方法来定义: F(0) = 0 F(1) = 1 F(n) = F( ...

  7. No package 'eventlog' found

    syslog-ng のインスト�ル手� ●ダウンロ�ドサイト http://www.balabit.com/downloads/files/syslog-ng/sources/stable/src/ ...

  8. docker-get拉取镜像

    docker-get Let you get all docker images without having network problem. Install curl -kLO https://s ...

  9. Vasya's Function CodeForces - 837E (gcd)

    大意: 给定$a,b$, $1\le a,b\le 1e12$, 定义 $f(a,0)=0$ $f(a,b)=1+f(a,b-gcd(a,b))$ 求$f(a,b)$. 观察可以发现, 每次$b$一定 ...

  10. Ubuntu编写开机启动脚本

    1 概述 服务器一般不可能百分之百不会挂,于是一般采用主备或者分布式来达到高可用. 挂掉的机器有很多处理策略,常用的就是重新启动,但是为了保证重启之后服务器能够恢复可用状态,需要配置开机启动脚本. 2 ...