题目大意:

给定A,B两种字符串,问他们当中的长度大于k的公共子串的个数有多少个

这道题目本身理解不难,将两个字符串合并后求出它的后缀数组

然后利用后缀数组求解答案

这里一开始看题解说要用栈的思想,觉得很麻烦就不做了,后来在比赛中又遇到就后悔了,到今天看了很久才算看懂

首先建一个栈,从栈底到栈顶都保证是单调递增的

我们用一个tot记录当前栈中所有项和一个刚进入的子串匹配所能得到的总的子串的数目(当然前提是,当前进入的子串height值比栈顶还大,那么和栈中任意一个子串匹配都保持当前栈中记录的那时候入栈的height值)

但是若height不比栈顶大,说明从栈顶开始到刚好比它小的这一段tot有多加的部分,这部分就是height值多出来的那块,然后把这部分都视作height值为当前的height值,因为后面子串进入,它的height值总是取决于那段区间的最小值,所以不会产生影响,这样就可以把所有比当前height大的都弹出栈,这样就达到了O(n)的复杂度

这里用q[][]手写栈

q[i][0]表示栈中第i号元素记录时候的height值,q[i][1]表示在这个height值上覆盖了q[i][1]个子串

 #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
const int MAXN = *;
int sa[MAXN] , rank[MAXN] , height[MAXN];
int wa[MAXN] , wb[MAXN] , wsf[MAXN] , wv[MAXN];
int a[MAXN] , k;
char str1[MAXN] , str2[MAXN];
int q[MAXN][]; int cmp(int *r , int a , int b , int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
} void getSa(int *r , int *sa , int n , int m)
{
int *x = wa , *y = wb , *t;
for(int i= ; i<m ; i++) wsf[i]=;
for(int i= ; i<n ; i++) wsf[x[i]=r[i]]++;
for(int i= ; i<m ; i++) wsf[i]+=wsf[i-];
for(int i=n- ; i>= ; i--) sa[--wsf[x[i]]] = i; int i,j,p=;
for(j= ; p<n ; j*= , m=p)
{
for(p= , i=n-j ; i<n ; i++) y[p++] = i;
for(i= ; i<n ; i++) if(sa[i]>=j) y[p++] = sa[i]-j; for(i= ; i<n ; i++) wv[i]=x[y[i]];
for(i= ; i<m ; i++) wsf[i]=;
for(i= ; i<n ; i++) wsf[wv[i]]++;
for(i= ; i<m ; i++) wsf[i]+=wsf[i-];
for(i=n- ; i>= ; i--) sa[--wsf[wv[i]]] = y[i]; for(t=x , x=y , y=t , x[sa[]]= , p= , i=; i<n ; i++)
x[sa[i]] = cmp(y , sa[i-] , sa[i] , j)?p-:p++;
}
return ;
} void callHeight(int *r , int *sa , int n)
{
for(int i= ; i<=n ; i++) rank[sa[i]]=i;
int i , j , k=;
for(i= ; i<n ; height[rank[i++]]=k)
for(j=sa[rank[i]-] , k?k--: ; r[i+k]==r[j+k] ; k++) ;
return;
} ll solve(int len1 , int len2)
{
ll ans = ;
//B串中的子串不断匹配rank比其高的A子串
int top = ;
ll tot = , cnt = ;
for(int i= ; i<=len1+len2+ ; i++){
if(height[i]<k){
top = tot = ;
continue;
}
cnt = ;
if(sa[i-]<len1){
cnt ++;
tot += height[i]-k+;
}
while(top&&height[i]<=q[top][]){
tot -= q[top][]*(q[top][]-height[i]);
cnt += q[top][];
top--;
}
q[++top][] = height[i];
q[top][] = cnt;
if(sa[i]>len1) ans+=tot;
}
//A串中的子串不断匹配rank比其高的B子串
tot = top = ;
for(int i= ; i<=len1+len2+ ; i++){
if(height[i]<k){
top = tot = ;
continue;
}
cnt = ;
if(sa[i-]>len1){
cnt ++;
tot += height[i]-k+;
}
while(top&&height[i]<=q[top][]){
tot -= q[top][]*(q[top][]-height[i]);
cnt += q[top][];
top--;
}
q[++top][] = height[i];
q[top][] = cnt;
if(sa[i]<len1) ans+=tot;
}
return ans;
} int main()
{
// freopen("a.in" , "r" , stdin); while(scanf("%d" , &k) , k)
{
scanf("%s%s" , str1 , str2);
int len1 = strlen(str1) , len2 = strlen(str2);
for(int i= ; i<len1 ; i++) a[i] = (int)str1[i];
a[len1] = ;
for(int i= ; i<len2 ; i++) a[i+len1+] = (int)str2[i];
a[len1+len2+] = ; getSa(a , sa , len1+len2+ , );
callHeight(a , sa , len1+len2+); // for(int i=0 ; i<len1+len2+2 ; i++) cout<<"rank i: "<<i<<" "<<rank[i]<<endl;
// for(int i=1 ; i<len1+len2+2 ; i++) cout<<"xixi: "<<height[i]<<endl;
ll ans = solve(len1 , len2);
printf("%I64d\n" , ans);
}
return ;
}

POJ 3415 后缀数组+单调栈的更多相关文章

  1. 【BZOJ-3238】差异 后缀数组 + 单调栈

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1561  Solved: 734[Submit][Status] ...

  2. BZOJ_3879_SvT_后缀数组+单调栈

    BZOJ_3879_SvT_后缀数组+单调栈 Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个 ...

  3. BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  4. BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)

    BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...

  5. 【BZOJ3879】SvT 后缀数组+单调栈

    [BZOJ3879]SvT Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干 ...

  6. BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】

    题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...

  7. BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】

    题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...

  8. poj 3415 Common Substrings(后缀数组+单调栈)

    http://poj.org/problem?id=3415 Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Sub ...

  9. poj 3415 Common Substrings——后缀数组+单调栈

    题目:http://poj.org/problem?id=3415 因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献. 一开始想 ...

随机推荐

  1. cnpm 下载

    1, 如果电脑已经有node的话,可以先卸载,然后再去node官网下载最新node, 2,先全局安装cnpm, npm install -g cnpm --registry=https://regis ...

  2. php 操作RabbitMQ

    本文摘抄自:https://www.cnblogs.com/alin-qu/p/8312874.html php 操作RabbitMQ   基本流程图 如果exchange 没有绑定queue,则消息 ...

  3. mysql 优化like查询

    1. like %keyword    索引失效,使用全表扫描.但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描. 2. like keyword%    索引有 ...

  4. ruby URI类

    一. URI require 'uri' uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413") # ...

  5. POJ2739 Sum of Consecutive Prime Numbers 确定某个数以内的所有素数

    参考:https://www.cnblogs.com/baozou/articles/4481191.html #include <iostream> #include <cstdi ...

  6. 【Java】关于Spring框架的总结 (二)

    上文提到了 Spring 的 IoC 特性和 AOP 特性,只提到个别的实现方法.本文将对 IoC 和 AOP 其他方法进行讲解. 多种方式实现依赖注入 1.设值注入 上文中使用的注入方法:通过 se ...

  7. Python入门及容易!网摘分享给大家!

    Python:Python学习总结 背景 PHP的$和->让人输入的手疼(PHP确实非常简洁和强大,适合WEB编程),Ruby的#.@.@@也好不到哪里(OO人员最该学习的一门语言). Pyth ...

  8. myeclipse 安装pydev插件后svn插件失效

    为了将python的IDE集成到myeclipse,按照教程安装了myeclipse插件pydev插件,但是按照完后发现,先前安装的svn不见了,解决办法如下: 1. 关闭myeclipse, 2. ...

  9. 如何在Moodle中显示PPT课件

    Moodle中目前是不直接支持PPT的,所以需要曲线救国: 1.安装 iSpring Free 8版本,免费版,其实是一个PPT的插件,在PPT的工具栏中有显示. 2.打开PPT后,直接在该工具中进行 ...

  10. 用 Qt 控制 Nikon 显微镜的电动物镜转盘

    用 Qt 控制 Nikon 显微镜的电动物镜转盘 最近的一个项目,用到了一台 Nikon 的金相显微镜,并且配了个电动的物镜转盘.为了控制这个电动物镜转盘,我折腾了差不多有4-5天.中间遇到了各种问题 ...