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. 【MEF】构建一个WPF版的ERP系统

    原文:[MEF]构建一个WPF版的ERP系统 引言 MEF是微软的一个扩展性框架,遵循某种约定将各个部件组合起来.而ERP系统的一大特点是模块化,它们两者的相性很好,用MEF构建一个ERP系统是相当合 ...

  2. MySQL清理慢查询日志slow_log的方法

    一.清除原因 因为之前打开了慢查询,导致此表越来越大达到47G,导致磁盘快被占满,使用xtrabackup进行备份的时候文件也超大. mysql> show variables like 'lo ...

  3. CS229笔记:生成学习算法

    在线性回归.逻辑回归.softmax回归中,学习的结果是\(p(y|x;\theta)\),也就是给定\(x\)的条件下,\(y\)的条件概率分布,给定一个新的输入\(x\),我们求出不同输出的概率, ...

  4. [CF1019C]Sergey's problem[构造]

    题意 找出一个集合 \(Q\),使得其中的点两两之间没有连边,且集合中的点可以走不超过两步到达其他所有不在集合中的点.输出任意一组解. \(n\leq 10^6\) 分析 考虑构造,先从 \(1\) ...

  5. 利用fiddler core api 拦截修改 websocket 数据

    一般的中间人攻击基本都是拦截修改普通的http协议里面的内容,而对于怎么拦截修改websocket协议传输的内容好像都没有多少介绍. talk is cheap show me the code us ...

  6. 记录:Ubuntu 18.04 安装 tensorflow-gpu 版本

    狠下心来重新装了系统,探索一下 gpu 版本的安装.比较令人可喜的是,跟着前辈们的经验,还是让我给安装成功了.由于我是新装的系统,就像婴儿般纯净,所以进入系统的第一步就是安装 cuda,只要这个不出错 ...

  7. Loadrunner 面试常见问题

    三大组件: 脚本生成器,录制和调试脚本 . 控制台,设置运行和资源场景 结果分析器,将测试结果数据以不同的图表呈现,便于性能分析 工作原理: 录制:根据不同协议,记录下客户端和服务器二者之间的对话,生 ...

  8. C++基础知识(3)

    C++内置的数据类型:基本类型.复合类型 基本类型:整型,浮点型,字符型 复合类型:数组,字符串,指针和结构 复合数据类型是在基本数据类型的基础上创建的 要知道系统中整数的最大长度,可以在程序中使用C ...

  9. [转]An overview of Openvswitch implementation

    This is NOT a tutorial on how to use openvswitch, this is for developers who want to know the implem ...

  10. hyperledger-fabirc1.2-ca-server的生产示例

    hyperledger-fabirc1.2-ca-server的生产示例,带TLS 在fabirc-samples/first-network中启动网络,其ca证书是利用crypto的工具生成的,但是 ...