http://poj.org/problem?id=3415 (题目链接)

题意

  给定两个字符串 A 和 B,求长度不小于 k 的公共子串的个数(可以相同)。

Solution

  后缀数组论文题。。。

  基本思路是计算 A 的所有后缀和 B 的所有后缀之间的最长公共前缀的长度,把最长公共前缀长度不小于 k 的部分全部加起来。先将两个字符串连起来,中间用一个没有出现过的字符隔开。按 height 值分组后,接下来的工作便是快速的统计每组中后缀之间的最长公共前缀之和。扫描一遍,每遇到一个 B 的后缀就统计与前面的 A 的后缀能产生多少个长度不小于 k 的公共子串,这里 A 的后缀需要用一个单调的栈来高效的维护。然后对 A 也这样做一次。

  如何用单调栈来维护呢?这真的是一个问题。这里我运用的单调栈与一般的单调栈不一样。单调栈里面记录一个结构体,结构体记录每个串对答案的贡献w以及这种串的个数c,自栈底向栈顶w递增。每次扫描到一个height[i]当它小于栈顶时,将栈顶的元素与栈顶第二个元素合并,并且更新栈中元素的总贡献。

细节

  数组开两倍。

代码

// poj3693
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=500010;
int sa[maxn],rank[maxn],height[maxn];
int n,K;
char s[maxn]; struct data {int w,c;}st[maxn];
namespace Suffix {
int wa[maxn],wb[maxn],ww[maxn];
bool cmp(int *r,int a,int b,int l) {
return r[a]==r[b] && r[a+l]==r[b+l];
}
void da(char *r,int *sa,int n,int m) {
int i,j,p,*x=wa,*y=wb;
for (i=0;i<=m;i++) ww[i]=0;
for (i=1;i<=n;i++) ww[x[i]=r[i]]++;
for (i=1;i<=m;i++) ww[i]+=ww[i-1];
for (i=n;i>=1;i--) sa[ww[x[i]]--]=i;
for (p=0,j=1;p<n;j*=2,m=p) {
for (p=0,i=n-j+1;i<=n;i++) y[++p]=i;
for (i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;
for (i=0;i<=m;i++) ww[i]=0;
for (i=1;i<=n;i++) ww[x[y[i]]]++;
for (i=1;i<=m;i++) ww[i]+=ww[i-1];
for (i=n;i>=1;i--) sa[ww[x[y[i]]]--]=y[i];
for (swap(x,y),p=x[sa[1]]=1,i=2;i<=n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p : ++p;
}
}
void calheight(char *r,int *sa,int n) {
for (int i=1;i<=n;i++) rank[sa[i]]=i;
for (int k=0,i=1;i<=n;i++) {
if (k) k--;
int j=sa[rank[i]-1];
while (r[i+k]==r[j+k]) k++;
height[rank[i]]=k;
}
}
} int main() {
while (scanf("%d",&K)!=EOF && K) {
scanf("%s",s+1);
int n=strlen(s+1);
s[++n]='#';
int l=n;
scanf("%s",s+n+1);
n=strlen(s+1);
Suffix::da(s,sa,n,300);
Suffix::calheight(s,sa,n);
int top=0;LL ans=0,S=0;
height[n+1]=inf;
for (int i=1;i<=n+1;i++) {
if (sa[i]>l && i!=n+1) ans+=S;
if (height[i+1]>=K) {
while (top>1 && st[top-1].w>height[i+1]-K+1) {
st[top-1].c+=st[top].c;
S-=(st[top].w-st[top-1].w)*st[top].c;
st[top--]=(data){0,0};
}
if (st[top].w>height[i+1]-K+1) {
if (st[top-1].w==height[i+1]-K+1) {
st[top-1].c+=st[top].c;
S-=(st[top].w-st[top-1].w)*st[top].c;
st[top--]=(data){0,0};
}
else {S-=(st[top].w-(height[i+1]-K+1))*st[top].c;st[top].w=height[i+1]-K+1;}
}
if (sa[i]<l) {
if (st[top].w==height[i+1]-K+1) st[top].c++;
else st[++top]=(data){height[i+1]-K+1,1};
S+=height[i+1]-K+1;
}
}
else {while (top) st[top--]=(data){0,0};S=0;}
}
for (int i=1;i<=n+1;i++) {
if (sa[i]<l && i!=n+1) ans+=S;
if (height[i+1]>=K) {
while (top>1 && st[top-1].w>height[i+1]-K+1) {
st[top-1].c+=st[top].c;
S-=(st[top].w-st[top-1].w)*st[top].c;
st[top--]=(data){0,0};
}
if (st[top].w>height[i+1]-K+1) {
if (st[top-1].w==height[i+1]-K+1) {
st[top-1].c+=st[top].c;
S-=(st[top].w-st[top-1].w)*st[top].c;
st[top--]=(data){0,0};
}
else {S-=(st[top].w-(height[i+1]-K+1))*st[top].c;st[top].w=height[i+1]-K+1;}
}
if (sa[i]>l) {
if (st[top].w==height[i+1]-K+1) st[top].c++;
else st[++top]=(data){height[i+1]-K+1,1};
S+=height[i+1]-K+1;
}
}
else {while (top) st[top--]=(data){0,0};S=0;}
}
printf("%lld\n",ans);
}
return 0;
}

【poj3415】 Common Substrings的更多相关文章

  1. 【POJ3415】 Common Substrings(后缀数组|SAM)

    Common Substrings Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤ ...

  2. 【POJ3415】Common Substrings(后缀数组,单调栈)

    题意: n<=1e5 思路: 我的做法和题解有些不同 题解是维护A的单调栈算B的贡献,反过来再做一次 我是去掉起始位置不同这个限制条件先算总方案数,再把两个串内部不合法的方案数减去 式子展开之后 ...

  3. 【POJ3415】 Common Substrings (SA+单调栈)

    这道是求长度不小于 k 的公共子串的个数...很不幸,我又TLE了... 解法参考论文以及下面的链接 http://www.cnblogs.com/vongang/archive/2012/11/20 ...

  4. 【SPOJ】Distinct Substrings(后缀自动机)

    [SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/e ...

  5. 【SPOJ】Distinct Substrings/New Distinct Substrings(后缀数组)

    [SPOJ]Distinct Substrings/New Distinct Substrings(后缀数组) 题面 Vjudge1 Vjudge2 题解 要求的是串的不同的子串个数 两道一模一样的题 ...

  6. 【CF316G3】Good Substrings 后缀自动机

    [CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中, ...

  7. 【Aizu2292】Common Palindromes(回文树)

    [Aizu2292]Common Palindromes(回文树) 题面 Vjudge 神TMD日语 翻译: 给定两个字符串\(S,T\),询问\((i,j,k,l)\)这样的四元组个数 满足\(S[ ...

  8. 【SPOJ】Distinct Substrings

    [SPOJ]Distinct Substrings 求不同子串数量 统计每个点有效的字符串数量(第一次出现的) \(\sum\limits_{now=1}^{nod}now.longest-paren ...

  9. 【POJ 3415】Common Substrings

    [链接]h在这里写链接 [题意]     求两个串的长度大于等于k的公共子串个数.     相同的重复计数. [题解]     先把两个字符串用一个分隔符分开.最好比出现的字符都大的一个数字.    ...

随机推荐

  1. go语言之行--包与变量

    一.包的概念 包是go语言中不可缺少部分,在每个go源码的第一行进行定义,定义方式是:package "包名",并且该名称是作为调用该包时候所使用的名称. 包的概念总结: 每个 G ...

  2. vue 打包后,后缀名为.woff等字体问题不能用解决办法

    1.打开 build / webpack.prod.conf.js ,找到 module: { rules: utils.styleLoaders({ sourceMap: config.build. ...

  3. Selenium 爬取全国水质周报Word

    很久没写爬虫了 ,昨天有个学姐说需要爬取水质的一些数据,给了个网站( http://xxfb.hydroinfo.gov.cn/ssIndex.html?type=2&tdsourcetag= ...

  4. 汇编 REPE/REPZ 指令,CMPSB指令

    知识点: REPE/REPZ 指令 CMPSB 指令 一.CMPSB //cmp //sub //SCASB//scasw//scasd cmp byte ptr [edi],al //对标志位的 ...

  5. mfc 类模板

    类模板 创建类模板 添加成员变量 添加成员函数 定义类模板对象 一.创建类模板 template <class T,class T2> template <class T> 二 ...

  6. 分享一下个人学PS的过程

    得知Photoshop这款软件是在上大学的时候,2010年.学校学生会的科技部纳新,要求新人会PPT.word.Excel和Photoshop.当时有一个Photoshop大神,成为了学生会科技部的主 ...

  7. win10+anaconda3+python3.6+opencv3.1.0

    最近用windows系统比较多,就想在win10下搞一下深度学习这一方面的研究,那么就需要配置好环境巴拉巴拉的一堆东西.默默记个笔记,正所谓“好记性不如烂笔头”. 1.安装Anaconda 这个是一个 ...

  8. proe工程图输出dwg/dxf文件设置

    网上看到不少人分享proe转转dxf/dwg配置文件的,但是看了一圈,几乎都没有涉及到转化线型的,所以自己整理自己的配置文件,写在这里分享出来. 以Pro/engineer WF5.0为例: 1.复制 ...

  9. Cooperate with Myself

    (一) 第一周的第一批作业们.  且不说一周之内要看完我们的300多页的教材,也不说需要在维基的大批量的文献中海底捞针,单是这个四则运算的生成程序就让我从假期的迷糊状态中幡然觉悟了:哦!惊险刺激的新的 ...

  10. Manjaro Linux 没有声音

    在Multimedia中的PulseAudio Volume Control中的设置可以解决