A substring of a string T is defined as:

                Tik)= TiTi +1... Ti+k -1, 1≤ i≤ i+k-1≤| T|.

Given two strings AB and one integer K, we define S, a set of triples (ijk):

S = {( ijk) | k≥ KAik)= Bjk)}.

You are to give the value of |S| for specific AB and K.

Input

The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.

1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.

Output

For each case, output an integer |S|.

Sample Input

2
aababaa
abaabaa
1
xx
xx
0

Sample Output

22
5

题意:

找出S,T两串中所有相同的长度大于等于K的字符串。不判重,即位置不同的相同串要重复统计。

解法:

  • 已知,对于一个串S,后缀自动机可以得到其所有的子串,以及递推出不同字串出现的数量num。
  • 对于匹配串T,一个字符一个字符的走一趟自动机(假设现在走到了T[i]),可以得到S中以T[i]结尾的集合,然后用集合中满足>=k的元素乘以num。
  • 里面有拓扑关系,用了lazy标记。
  • 加了输入优化,时间排名第三。

注意:

ans=ans+(long long)lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+)+)*num[p];

开始把long long的位置写错了,wa了很多次。

错误位置:ans=(long long)ans+lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+)+)*num[p];

(难道是先执行乘法,这个时候long long无效?)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;
const int maxn=;
int K;char chr[maxn];
struct SAM
{
int sz,Last,ch[maxn][],slink[maxn],maxlen[maxn];
int c[maxn],pos[maxn],num[maxn],lazy[maxn];
//num表示一个模板串S中x集合出现的次数,lazy表示匹配串T中x集合的累加(向上slink(fa)传递)。
//pos是拓扑排序后的结果,用来递推num和lazy。
long long ans;
int get(char x)
{
if(x>='a'&&x<='z') return x-'a';
return x-'A'+;
}
void init()
{
sz=; Last=sz=;
memset(ch[],,sizeof(ch[]));
num[]=lazy[]=;
}
void add(int x)
{
int np=++sz,p=Last;Last=np;
lazy[sz]=;num[sz]=;
maxlen[np]=maxlen[p]+;
memset(ch[np],,sizeof(ch[np]));
while(p&&!ch[p][x]) ch[p][x]=np,p=slink[p];
if(!p) slink[np]=;
else {
int q=ch[p][x];
if(maxlen[q]==maxlen[p]+) slink[np]=q;
else {
int nq=++sz; lazy[sz]=num[sz]=;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
slink[nq]=slink[q],slink[np]=slink[q]=nq;
maxlen[nq]=maxlen[p]+;
while(p&&ch[p][x]==q) ch[p][x]=nq,p=slink[p];
}
}
}
void sort()
{
for(int i=;i<=sz;i++) c[i]=;
for(int i=;i<=sz;i++) c[maxlen[i]]++;
for(int i=;i<=sz;i++) c[i]+=c[i-];
for(int i=;i<=sz;i++) pos[c[maxlen[i]]--]=i;
for(int i=sz;i>=;i--) num[slink[pos[i]]]+=num[pos[i]];
}
void solve()
{
char c=getchar();
while(!(c>='a'&&c<='z')&&!(c>='A'&&c<='Z')) c=getchar();
int mp=,Len=;ans=;
while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) {
int x=get(c);c=getchar();
if(ch[mp][x]){ Len++; mp=ch[mp][x];}
else {
while(mp&&!ch[mp][x]) mp=slink[mp];
if(!mp) { mp=; Len=; }//~
else { Len=maxlen[mp]+; mp=ch[mp][x]; }
}
if(Len>=K) {
ans=(long long)ans+(Len-max(maxlen[slink[mp]]+,K)+)*num[mp];
if(maxlen[slink[mp]]>=K) lazy[slink[mp]]++;
}
}
for(int i=sz;i>=;i--) {
int p=pos[i];
ans=ans+(long long)lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+)+)*num[p];
if(maxlen[slink[p]]>=K) lazy[slink[p]]+=lazy[p];
}
printf("%lld\n",ans);
}
};
SAM sam;
int main()
{
while(~scanf("%d",&K)){
if(K==) return ;
sam.init();
char c=getchar();
while(!(c>='a'&&c<='z')&&!(c>='A'&&c<='Z')) c=getchar();
while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) sam.add(sam.get(c)),c=getchar();
sam.sort();
sam.solve();
}
return ;
}

POJ3415Common Substrings(后缀自动机)的更多相关文章

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

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

  2. SPOJ NSUBSTR Substrings 后缀自动机

    人生第一道后缀自动机,总是值得纪念的嘛.. 后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边.许多铺垫的 ...

  3. ●SPOJ 8222 NSUBSTR–Substrings(后缀自动机)

    题链: http://www.spoj.com/problems/NSUBSTR/ 题解: 后缀自动机的水好深啊!懂不了相关证明,带着结论把这个题做了.看来这滩深水要以后再来了. 本题要用到一个叫 R ...

  4. SPOJ8222 NSUBSTR - Substrings(后缀自动机)

    You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as ...

  5. SPOJ NSUBSTR Substrings ——后缀自动机

    建后缀自动机 然后统计次数,只需要算出right集合的大小即可, 然后更新f[l[i]]和rit[i]取个max 然后根据rit集合短的一定包含长的的性质,从后往前更新一遍即可 #include &l ...

  6. spoj 8222 Substrings (后缀自动机)

    spoj 8222 Substrings 题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.求F(1)..F(Length(S)) 解题思路:我们构造S的SAM,那么对于 ...

  7. UVA - 10829 L-Gap Substrings (后缀自动机+线段树启发式合并)

    题意:统计一段字符串中形如UVU的子串个数(其中V的长度固定为g). 问题等价于求满足$g+1\leqslant |j-i|\leqslant g+LCP(i,j)$的后缀(i,j)的对数,即$\su ...

  8. SPOJ8222 Substrings( 后缀自动机 + dp )

    题目大意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.F(1)..F(Length(S)) 建出SAM, 然后求出Right, 求Right可以按拓扑序dp..Right ...

  9. SPOJ8222 NSUBSTR - Substrings 后缀自动机_动态规划

    讲起来不是特别好讲.总之,如果 $dp[i+1]>=dp[i]$,故$dp[i]=max(dp[i],dp[i+1])$ Code: #include <cstdio> #inclu ...

  10. SP8222 NSUBSTR - Substrings(后缀自动机+dp)

    传送门 解题思路 首先建出\(sam\),然后把\(siz\)集合通过拓扑排序算出来.对于每个点只更新它的\(maxlen\),然后再从大到小\(dp\)一次就行了.因为\(f[maxlen-1]&g ...

随机推荐

  1. SpringMVC必备知识点汇总

    1.参数接收 1.1 数组 1.2 文件上传 1.2.1 单个文件上传 1.2.2 多个文件上传 1.2.3 文件上传时,携带其他数据 2.参数校验 参数校验:https://www.cnblogs. ...

  2. 用Python快速找到出现次数最多的数据

    给你一个文件,每行一个iip?

  3. # vmware异常关机后,虚拟系统无法启动的解决办法

    vmware异常关机后,虚拟系统无法启动的解决办法 先使用everything搜索所有后缀为.lck的文件,这些文件全部删除,如果不确定是否可以删除,先把这些文件转移到桌面,等能启动虚拟系统之后再删除 ...

  4. Python_4day

    函数 函数可以用来定义可重复代码,组织和简化 一般来说一个函数在实际开发中为一个小功能 一个类为一个大功能 同样函数的长度不要超过一屏   Python中的所有函数实际上都是有返回值(return N ...

  5. 用纯 CSS 创作一个在容器中反弹的小球

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/jKVbyE 可交互视频教 ...

  6. CentOS 7 yum安装LAMP,LNMP并搭建WordPress个人博客网站

    本次实验要进行的是在CentOS7.2,内核版本3.10.0-327.el7.x86_64的环境下搭建LAMP和LNMP,并在此之上做一个WordPress博客网站. [root@Shining ~] ...

  7. Linux-1.2关机重启reboot,shutdown

    关机重启:reboot,shutdown reboot 重启操作系统 shutdown -r now 重启,shutdown会给其他用户提示

  8. bash 转换为C代码

    bash 转换为C代码,并编译为可执行文件 [root@localhost ~]# wget http://www.datsi.fi.upm.es/~frosal/sources/shc-3.8.9. ...

  9. 解决mac下brew install报错

    Error: Another active Homebrew update process is already in progress.Please wait for it to finish or ...

  10. Mysql学习(三)之数据库管理工具Navicat

    前言 mysql安装完后默认只有命令行工具,所以我们可以下载一些数据库管理工具Navicat Navicat使用 首先建立一个连接选择mysql,填写信息 发现多了一个localhost,双击,打开连 ...