POJ3415Common Substrings(后缀自动机)
A substring of a string T is defined as:
T( i, k)= TiTi +1... Ti+k -1, 1≤ i≤ i+k-1≤| T|.
Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):
S = {( i, j, k) | k≥ K, A( i, k)= B( j, k)}.
You are to give the value of |S| for specific A, B 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(后缀自动机)的更多相关文章
- 【CF316G3】Good Substrings 后缀自动机
[CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中, ...
- SPOJ NSUBSTR Substrings 后缀自动机
人生第一道后缀自动机,总是值得纪念的嘛.. 后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边.许多铺垫的 ...
- ●SPOJ 8222 NSUBSTR–Substrings(后缀自动机)
题链: http://www.spoj.com/problems/NSUBSTR/ 题解: 后缀自动机的水好深啊!懂不了相关证明,带着结论把这个题做了.看来这滩深水要以后再来了. 本题要用到一个叫 R ...
- SPOJ8222 NSUBSTR - Substrings(后缀自动机)
You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as ...
- SPOJ NSUBSTR Substrings ——后缀自动机
建后缀自动机 然后统计次数,只需要算出right集合的大小即可, 然后更新f[l[i]]和rit[i]取个max 然后根据rit集合短的一定包含长的的性质,从后往前更新一遍即可 #include &l ...
- spoj 8222 Substrings (后缀自动机)
spoj 8222 Substrings 题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.求F(1)..F(Length(S)) 解题思路:我们构造S的SAM,那么对于 ...
- UVA - 10829 L-Gap Substrings (后缀自动机+线段树启发式合并)
题意:统计一段字符串中形如UVU的子串个数(其中V的长度固定为g). 问题等价于求满足$g+1\leqslant |j-i|\leqslant g+LCP(i,j)$的后缀(i,j)的对数,即$\su ...
- SPOJ8222 Substrings( 后缀自动机 + dp )
题目大意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.F(1)..F(Length(S)) 建出SAM, 然后求出Right, 求Right可以按拓扑序dp..Right ...
- SPOJ8222 NSUBSTR - Substrings 后缀自动机_动态规划
讲起来不是特别好讲.总之,如果 $dp[i+1]>=dp[i]$,故$dp[i]=max(dp[i],dp[i+1])$ Code: #include <cstdio> #inclu ...
- SP8222 NSUBSTR - Substrings(后缀自动机+dp)
传送门 解题思路 首先建出\(sam\),然后把\(siz\)集合通过拓扑排序算出来.对于每个点只更新它的\(maxlen\),然后再从大到小\(dp\)一次就行了.因为\(f[maxlen-1]&g ...
随机推荐
- pandas中.value_counts()用于统计数据集中的某一列
value_counts()是一种查看表格某列中有多少个不同值的快捷方法,并计算每个不同值有在该列中有多少重复值.value_counts()是Series拥有的方法,一般在DataFrame中使用时 ...
- Oracle 自增序列的生成
1.代码结构 .创建 第一种 -- Create sequence create sequence SEQ_USERID minvalue maxvalue start increment nocac ...
- Linux基础命令训练题型(上)
1.创建目录/data/dongdaxia,并且在该目录下创建文件dongdaxia.txt,然后在文件dongdaxia.txt里写入内容“inet 192.168.221.132 netmask ...
- [转帖]yum命令的使用与createrepo自建仓库教程
yum命令的使用与createrepo自建仓库教程 http://www.linuxe.cn/post-300.html 跟上篇一样 可以学习一下. 发布:TangLu2018-11-23 16:48 ...
- 小菜鸟之Cisco
Switch>enable// Switch#configure// Switch#show vlan//展示vlan接口 Switch(config)#enable password 1234 ...
- Python学习【day05】- Python文件处理
一.打开文件 对文件的操作主要为三步:1.打开文件,得到文件句柄.2.通过句柄对文件进行操作.3.关闭文件 # 默认打开模式为r,encoding默认为系统文件编码 f=open('F:/Go.txt ...
- springboot 用redis缓存整合spring cache注解,使用Json序列化和反序列化。
springboot下用cache注解整合redis并使用json序列化反序列化. cache注解整合redis 最近发现spring的注解用起来真的是很方便.随即产生了能不能吧spring注解使用r ...
- 如何用纯 CSS 创作一个晃动的公告板
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/wjZoGV 可交互视频教 ...
- Tensorflow常见函数case argmax equal
常用的函数: tf.argmax(input, axis=None, name=None, dimension=None) input:输入Tensor axis:0表示按列,1表示按行 name:名 ...
- Linux中使用curl命令发送带参数的get请求和post请求
GET 请求 curl命令 + 请求接口的地址 curl http://**.**.***.**/SeedAgile/SeedApi/querySprintByRequirementNo?parame ...