POJ 3415 后缀数组+单调栈
题目大意:
给定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 后缀数组+单调栈的更多相关文章
- 【BZOJ-3238】差异 后缀数组 + 单调栈
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1561 Solved: 734[Submit][Status] ...
- BZOJ_3879_SvT_后缀数组+单调栈
BZOJ_3879_SvT_后缀数组+单调栈 Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个 ...
- BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈
BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- 【BZOJ3879】SvT 后缀数组+单调栈
[BZOJ3879]SvT Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干 ...
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- poj 3415 Common Substrings(后缀数组+单调栈)
http://poj.org/problem?id=3415 Common Substrings Time Limit: 5000MS Memory Limit: 65536K Total Sub ...
- poj 3415 Common Substrings——后缀数组+单调栈
题目:http://poj.org/problem?id=3415 因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献. 一开始想 ...
随机推荐
- vue服务端渲染添加缓存
缓存 虽然 Vue 的服务器端渲染(SSR)相当快速,但是由于创建组件实例和虚拟 DOM 节点的开销,无法与纯基于字符串拼接(pure string-based)的模板的性能相当.在 SSR 性能至关 ...
- Hue联合(hdfs yarn hive) 后续......................
1.启动hdfs,yarn start-all.sh 2.启动hive $ bin/hive $ bin/hive --service metastore & $ bin/hive --ser ...
- 如何用Python做自动化特征工程
机器学习的模型训练越来越自动化,但特征工程还是一个漫长的手动过程,依赖于专业的领域知识,直觉和数据处理.而特征选取恰恰是机器学习重要的先期步骤,虽然不如模型训练那样能产生直接可用的结果.本文作者将使用 ...
- Leecode刷题之旅-C语言/python-136只出现一次的数字
/* * @lc app=leetcode.cn id=136 lang=c * * [136] 只出现一次的数字 * * https://leetcode-cn.com/problems/singl ...
- Matplotlib 基本图表的绘制
图表类别:线形图.柱状图.密度图,以横纵坐标两个维度为主 同时可延展出多种其他图表样式 plt.plot(kind='line', ax=None, figsize=None, use_index=T ...
- UVa Problem 100 The 3n+1 problem (3n+1 问题)
参考:https://blog.csdn.net/metaphysis/article/details/6431937 #include <iostream> #include <c ...
- Bootstrap4用法
#Bootstrap4 ## 网格系统- .col- 针对所有设备- .col-sm- 平板 - 屏幕宽度等于或大于 576px- .col-md- 桌面显示器 - 屏幕宽度等于或大于 768px)- ...
- Linux 下 PHP 扩展 PDO 编译安装
1.进入 PHP 的软件包 pdo 扩展目录中(注:不是 PHP 安装目录) [root@tester /]# /home/tdweb/php-5.4.34/ext/pdo_mysql 执行 phpi ...
- kindeditor 限制上传图片大小及宽高
进入:/kindeditor/plugins/image/image.js,替换其中的 self.plugin.imageDialog = function (options)方法,代码为: self ...
- 《python核心编程第二版》第7章习题
7–1. 字典方法.哪个字典方法可以用来把两个字典合并到一起? 答:dict1.update(dict2) 7–2. 字典的键.我们知道字典的值可以是任意的Python 对象,那字典的键又如何呢?请试 ...