POJ 3415 Common Substrings(后缀数组 + 单调栈)题解
题意:
给两个串\(A、B\),问你长度\(>=k\)的有几对公共子串
思路:
先想一个朴素算法:
把\(B\)接在\(A\)后面,然后去跑后缀数组,得到\(height\)数组,那么直接\(rmq\)就能\(O(1)\)得到任意两个\(A\)和\(B\)的LCP。如果\(LCP >= k\),那么这个串的贡献对数为\(LCP - k + 1\)。但是这样遍历显然超时。
那么我们可以用单调栈优化这个问题:
我们构建一个递增的单调栈,那么栈顶就是最大,每个栈里的元素为贡献值\(height\)的大小,那么显然,某一位置对后面的贡献为\(min(height[i])\),所以如果遇到入栈元素比栈顶大,说明栈顶的贡献值从此刻开始就要变小了,那么就去更新这个贡献。
参考:
代码:
#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++){ //栈里塞A
if(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++){ //栈里塞B
if(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;
}
POJ 3415 Common Substrings(后缀数组 + 单调栈)题解的更多相关文章
- poj 3415 Common Substrings —— 后缀数组+单调栈
题目:http://poj.org/problem?id=3415 先用后缀数组处理出 ht[i]: 用单调栈维护当前位置 ht[i] 对之前的 ht[j] 取 min 的结果,也就是当前的后缀与之前 ...
- poj 3415 Common Substrings——后缀数组+单调栈
题目:http://poj.org/problem?id=3415 因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献. 一开始想 ...
- poj 3415 Common Substrings 后缀数组+单调栈
题目链接 题意:求解两个字符串长度 大于等于k的所有相同子串对有多少个,子串可以相同,只要位置不同即可:两个字符串的长度不超过1e5; 如 s1 = "xx" 和 s2 = &qu ...
- poj 3415 Common Substrings - 后缀数组 - 二分答案 - 单调栈
题目传送门 传送点I 传送点II 题目大意 给定串$A, B$,求$A$和$B$长度大于等于$k$的公共子串的数量. 根据常用套路,用一个奇怪的字符把$A$,$B$连接起来,然后二分答案,然后按mid ...
- POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)
Description A substring of a string T is defined as: T( i, k)= TiTi+1... Ti+k-1, 1≤ i≤ i+k-1≤| T|. G ...
- POJ3415 Common Substrings —— 后缀数组 + 单调栈 公共子串个数
题目链接:https://vjudge.net/problem/POJ-3415 Common Substrings Time Limit: 5000MS Memory Limit: 65536K ...
- POJ 3415 Common Substrings 后缀数组+并查集
后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height 求完之后按height值从大往小合并. height值代表的是 sa[i]和sa[i ...
- POJ - 3415 Common 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 s ...
- poj 3415 Common Substrings【SA+单调栈】
把两个串中间加一个未出现字符接起来,然后求SA 然后把贡献统计分为两部分,在排序后的后缀里,属于串2的后缀和排在他前面属于串1的后缀的贡献和属于串1的后缀和排在他前面属于串2的后缀的贡献 两部分分别作 ...
- POJ 3415 Common Substrings ——后缀数组
[题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #inclu ...
随机推荐
- 前端知识(二)08-Vue.js的路由-谷粒学院
目录 一.锚点的概念 二.路由的作用 三.路由实例 1.复制js资源 2.创建 路由.html 3.引入js 4.编写html 5.编写js 一.锚点的概念 案例:百度百科 特点:单页Web应用,预先 ...
- NAT模式、路由模式、桥接模式的区别
NAT模式 NAT模式概述 NAT是"Network Address Translation"的缩写,中文意思是"网络地址转换",它允许一个整体机构以一个公用I ...
- Spring Cloud 2020.0.1 正式发布!真是头疼。。。
上一篇:Spring Cloud 2020.0.0 正式发布,全新颠覆性版本! 号外!号外!号外! Spring Cloud 2020.0.0 在去年 12 月底,赶在一年的尾巴最后几天仓促发布了,时 ...
- 在IDEA中用三个jar包链接MongoDB数据库——实现增删改查
安装Robo 3T连接MongoDB数据库教程:https://blog.csdn.net/baidu_39298625/article/details/98845789 使用Robo 3T操作Mon ...
- Python学习【第8篇】:python中的函数
1.python中函数定义方法 def test(x): "This istest" y = x*2+1 return y vaule = test(2)print(vaule)运 ...
- 十六:SpringBoot-自定义启动页,项目打包和指定运行环境
SpringBoot-自定义启动页,项目打包和指定运行环境 1.自定义启动页 2.打包配置 2.1 打包pom配置 2.2 多环境配置 3.环境测试接口 4.打包执行 4.1 指定模块打包 4.2 运 ...
- Go语言学习笔记(4)——并发编程
Golang在语言级别支持了协程,由runtime进行管理. 在Golang中并发执行某个函数非常简单: func Add(x, y int) { fmt.Println(x + y) } func ...
- linux环境变量 shell变量 command not found解决方法(转)
在Ubuntu.centos中有如下几个文件可以设置环境变量1./etc/profile:在登录时,操作系统定制用户环境时使用的第一个文件,此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文 ...
- SANGFOR AC配置AD域单点登录(一)----AC侧配置
一.需求 1. AD域单点登录适用于客户内网已有AD域统一管理内网用户,部署AC后,希望AC和AD域结合实现平滑认证.即终端PC开机通过域帐号登录AD域后自动通过AC认证上网,无需再次人为通过AC认证 ...
- VS CODE一些常见配置操作(快捷键设置、C/C++的debug、代码路径配置)
总述 今天来一篇简单的操作文章吧,VSCODE是我们经常用的软件,我之前也写过关于VSCODE远程办公的一些的操作(有兴趣的朋友可以点击进去看看),今天我再稍微介绍一些我其他地方用到的一些操作 ...