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. PX Deq: Execution Msg 等待事件

    可参考 MOS文档: WAITEVENT: "PX Deq Credit: send blkd" (Doc ID 271767.1) P1 = sleeptime/senderid ...

  2. 不成功的RMAN恢复到其他机器的例子

    事实上,RMAN备份的时候,如果是使用control file 来作catalog,那么一定要把control file和spfile恢复到另外的机器上面. 否则,会出现类似如下的错误: 原来的实例: ...

  3. MiZ702学习笔记8——让MiZ702变身PC的方法

    首先你需要一个安装好的linux系统,这里我用的是Ubuntu的虚拟机.VMWare的话,选择较高版本的成功率会高些(当然根据自己电脑的配置进行选择). 打开Ubuntu的虚拟机,找到一个叫做Disk ...

  4. Asp.net MVC Razor常见问题及解决方法(转载>云中客)

    没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: 1 2 ...

  5. 杂谈---小故事小道理,面试中的小技巧(NO.2)

    本篇是接着上一篇面试随笔的,上一次有猿友反应写的有些“扯淡”,LZ思来想去最大的原因可能是由于上一章写的全是一些大忌,既然是大忌,那么在现实当中发生的概率还是相对较小的,大部分人还是很少在面试中犯如此 ...

  6. python基础篇----基本数据类型

    bit  #bit_length 当前数字的二进制,只用用n位来表示a = 123b = a.bit_length()print(b)#==>7

  7. JMeter的下载安装以及运行教程

    一.安装JMeter的必要准备 1.安装JDK JDK下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html ...

  8. 以太坊—P2P网络

    Chord算法 1.Chord 概念 Chrod算法是P2P中的四大算法之一,是有MIT(麻省理工学院)于2001年提出 . Chord的目的是提供一种能在P2P网络快速定位资源的的算法,Chord并 ...

  9. hive insert 动态分区异常(Error encountered near token)与解决

    当insert数据到有分区的hive表里时若不明显指定分区会抛出异常 insert overwrite table persons_tmp select * from persons; FAILED: ...

  10. M1阶段事后总结

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述?我们组要爬取网上的内容供下一组使用,定义的不太清楚,因为用户只有下一个团队所以没有进行详细的需求分析 ...