题目大意:

给定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. php-语言参考-类型3.2-未完待续

    一,PHP变量的8个类型 四种标量类型: boolean (布尔型) integer (整型) float (浮点型, 也称作 double) string (字符串) 两种复合类型: array ( ...

  2. 在python中安装basemap

    在python中安装basemap 1. 确保python环境安装完毕且已配置好环境变量 2. 安装geos: pip install geos 3. 下载.whl文件: (1)pyproj‑1.9. ...

  3. 09 mongoDB基础(进阶)

    mongoDB基础 阶段一.认识mongodb 1.mongodb 组织数据的基本形式 MongoDB————>数据库————>集合————>文档 mysql:表:行和列:字段 运用 ...

  4. R语言学习笔记(十):零碎知识点(21-25)

    21--assign() assign函数可以通过变量名的字符串来赋值 > assign('a', 1:3) > a [1] 1 2 3 > b <- c('a') > ...

  5. 43-Identity MVC:UI

    1-打开之前写的MvcCookieAuthSample项目, 在AccountController新加Register,Login方法 public class AccountController : ...

  6. Union-find 并查集

    解决问题 给一系列对点0~N-1的连接,判断某两个点p与q是否相连. private int[] id; // 判断p和q是否属于同一个连通分量 public boolean connected(in ...

  7. django序列化时间

    具体代码: import json,time,datetime lis ={'time':datetime.date.today(),"username":"zhilei ...

  8. 如何理解Java中参数传递只能传值?

    以前学习C#的时候,是完全在工作岗位上学习,一些底层较为深入的道理都不是很清楚.如今学习了Java,对于Java参数传递只能传值,不能传引用(指针)感到很困惑,在C#中不是常常说把某个引用传递到函数中 ...

  9. (原)一段看似美丽的for循环,背后又隐藏着什么

    之前很长一段时间,潜心修炼汇编,专门装了一个dos7,慢慢玩到win32汇编,再到linux的AT&A汇编,尝试写mbr的时候期间好几次把centos弄的开不了机,又莫名其妙的修好了,如今最大 ...

  10. 25、react入门教程

    0. React介绍 0.1 什么是React? React(有时称为React.js 或ReactJS)是一个为数据提供渲染HTML视图的开源JavaScript库. 它由FaceBook.Inst ...