题意:

给两个串\(A、B\),问你长度\(>=k\)的有几对公共子串

思路:

先想一个朴素算法:
把\(B\)接在\(A\)后面,然后去跑后缀数组,得到\(height\)数组,那么直接\(rmq\)就能\(O(1)\)得到任意两个\(A\)和\(B\)的LCP。如果\(LCP >= k\),那么这个串的贡献对数为\(LCP - k + 1\)。但是这样遍历显然超时。
那么我们可以用单调栈优化这个问题:
我们构建一个递增的单调栈,那么栈顶就是最大,每个栈里的元素为贡献值\(height\)的大小,那么显然,某一位置对后面的贡献为\(min(height[i])\),所以如果遇到入栈元素比栈顶大,说明栈顶的贡献值从此刻开始就要变小了,那么就去更新这个贡献。

参考:

POJ 3415 Common Substrings

代码:

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ull seed = 11;
const int MOD = 1e9 + 7;
using namespace std;int str[maxn];
int t1[maxn], t2[maxn], c[maxn];
int sa[maxn];
int rk[maxn];
int height[maxn];
bool cmp(int *r, int a, int b, int l){return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *str, int n, int m){n++;int i, j, p, *x = t1, *y = t2;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = str[i]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;for(j = 1; j <= n; j <<= 1){p = 0;for(i = n - j; i < n; i++) y[p++] = i;for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[y[i]]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];swap(x, y);p = 1; x[sa[0]] = 0;for(i = 1; i < n; i++)x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;if(p >= n) break;m = p;}int k = 0;n--;for(i = 0; i <= n; i++) rk[sa[i]] = i;for(i = 0; i < n; i++){if(k) k--;j = sa[rk[i] - 1];while(str[i + k] == str[j + k]) k++;height[rk[i]] = k;}
}
char s[maxn];
ll instack[maxn], num[maxn];
int main(){int k;while(~scanf("%d", &k) && k){scanf("%s", s);int len = strlen(s);int cnt = 0;for(int i = 0; i < len; i++){str[cnt++] = s[i];}int pos = cnt;  //#str[cnt++] = '$';scanf("%s", s);len = strlen(s);for(int i = 0; i < len; i++){str[cnt++] = s[i];}str[cnt] = 0;da(str, cnt, 130);int top = 0;ll tot = 0, ans = 0;for(int i = 2; i <= cnt; i++){   //栈里塞Aif(height[i] < k){top = 0, tot = 0;}else{int number = 0;if(sa[i - 1] < pos){    //A对后面B的贡献tot += height[i] - k + 1;number++;}while(top > 0 && instack[top] >= height[i]){tot -= num[top] * (instack[top] - k + 1);tot += num[top] * (height[i] - k + 1);number += num[top];--top;}instack[++top] = height[i];num[top] = number;if(sa[i] > pos) ans += tot;}}top = 0, tot = 0;for(int i = 2; i <= cnt; i++){   //栈里塞Bif(height[i] < k){top = 0, tot = 0;}else{int number = 0;if(sa[i - 1] > pos){    //B对后面A的贡献tot += height[i] - k + 1;number++;}while(top > 0 && instack[top] >= height[i]){tot -= num[top] * (instack[top] - k + 1);tot += num[top] * (height[i] - k + 1);number += num[top];--top;}instack[++top] = height[i];num[top] = number;if(sa[i] < pos) ans += tot;}}printf("%lld\n", ans);}return 0;
}

转载于:https://www.cnblogs.com/KirinSB/p/11271291.html

POJ 3415 Common Substrings(后缀数组 + 单调栈)题解相关推荐

  1. POJ - 3415 Common Substrings(后缀数组+单调栈)

    题目链接:点击查看 题目大意:给出两个字符串,再给出一个k,问两个字符串中长度大于等于k的公共子串有多少个(种类可重复) 题目分析:因为涉及到了子串问题,先用后缀数组跑出height数组来,接下来如果 ...

  2. POJ - 3415 Common Substrings(长度不小于K的公共子串个数)

    Common Substrings 后缀数组+单调栈 题解1 题解2 题解3 #include<cstdio> #include<cstring> #include<io ...

  3. POJ 3415 后缀数组+单调栈

    题目大意: 给定A,B两种字符串,问他们当中的长度大于k的公共子串的个数有多少个 这道题目本身理解不难,将两个字符串合并后求出它的后缀数组 然后利用后缀数组求解答案 这里一开始看题解说要用栈的思想,觉 ...

  4. [BZOJ3238][AHOI2013]差异 [后缀数组+单调栈]

    题目地址 - GO-> 题目大意: 给定一个长度为 nn 的字符串SS,令TiTi表示它从第ii个字符开始的后缀,求以下这个式子的值: ∑1≤i<j≤nlen(Ti)+len(Tj)−2× ...

  5. [Ahoi2013]差异[后缀数组+单调栈]

    链接 解题思路:很明显前面∑1<=i<j<=nlen(Ti)+len(Tj)\sum_{1<=i<j<=n}len(T_i)+len(T_j)∑1<=i< ...

  6. POJ 3415 Common Substrings

    Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given t ...

  7. [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】

    题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...

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

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

  9. [bzoj3238]差异(后缀数组+单调栈)

    显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是 ...

  10. 【BZOJ3879】SvT,后缀数组+单调栈维护sum

    Time:2016.08.15 Author:xiaoyimi 转载注明出处谢谢 如果有不明白的地方可以在下面评论问我 传送门 思路: 建立后缀数组求出Height 如果说对每次询问暴力求LCP累加的 ...

最新文章

  1. DIKW体系(Data-Information-Knowlege-Wisdom)
  2. Java基础-JAVA中常见的数据结构介绍
  3. 关于SQL 数据库表中的聚集索引和非聚集索引等
  4. OutOfMemoryException异常解析
  5. hive实例,GPRS流量统计
  6. JBox2D手机游戏引擎介绍(附jbox2d官网网址)
  7. Phonegap集成angular/bootstrap/animate.css教程
  8. Android获取EditText,Spinner,CheckBox,RadioButton信息Toast显示
  9. POI中sheet.getRow方法返回值NullPointException
  10. php 判断是否是16进制,如何求解16进制字符串的验证
  11. MySQL 基数的定义
  12. 基于vue-cli的快速开发框架
  13. 【mock】数据模板定义规范DTD 数据占位符定义规范DPD
  14. 网站CDN 判断 绕过方法
  15. 新型城镇化3.0时代 数据交换是“智慧城市”的核心
  16. (2)防火墙的基本配置---1安全域和端口
  17. “似水无形” 的小程序化
  18. (转)东方美人吉他谱及演奏(中川砂仁)
  19. Pygame pgu 入门详解
  20. 唯品会开盘股价超过8美元 市值再超当当网

热门文章

  1. 二分类问题的评分值与损失函数
  2. 【遥感影像】Python GDAL 像素与坐标对应
  3. 兄dei,来封装一个自定义事件玩玩
  4. WPF—TreeView无限极绑定集合形成树结构
  5. hibernate查询list结果集结果都是一样
  6. [基础] Array.prototype.indexOf()查询方式
  7. NGINX反向代理部署
  8. [Android动画] 补间动画-动画工具类( AnimationUtils)七
  9. 思科和华为交换机常用命令对比学习
  10. LSI SAS 3008配置操作