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 two strings A, B and one integer K, we define S, a set of triples (i, j, k):
S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}.
You are to give the value of |S| for specific A, B and K.
Input
The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.
1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.
Output
For each case, output an integer |S|.
题目大意:给两个字符串,问有多少个长度大于等于K的公共子串。
思路:首先,把两个字符串用一个未出现过的字符(如'$')连起来,求后缀数组和height[]数组。
用每个后缀的所有前缀代表一个字符串的所有子串。
然后,按height[]的顺序从前往后扫描。
遇到第一个字符串的,就压入栈中。遇到第二个字符串的,就计算栈中与第二个字符串的长度大于等于K的公共前缀。
对于栈中每一个height[],它与当前第二个字符串的长度大于等于K的公共前缀一共有height[]-k+1个。
sum{height[]-k+1}可以在压栈的同时统计。
用一个单调栈维护,让每个height[]只入栈和出栈一次。
最后rank小的第一个字符串和rank大的第二个字符串的长度大于等于K的公共前缀就统计出来了,统计复杂度为O(n)。
此时两个字符串反过来再做一遍即可。
代码(1469MS):
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long LL; const int MAXN = ; char s[MAXN];
int sa[MAXN], rank[MAXN], height[MAXN], c[MAXN], tmp[MAXN];
int n, apart, k; void makesa(int m) {
memset(c, , m * sizeof(int));
for(int i = ; i < n; ++i) ++c[rank[i] = s[i]];
for(int i = ; i < m; ++i) c[i] += c[i - ];
for(int i = ; i < n; ++i) sa[--c[rank[i]]] = i;
for(int k = ; k < n; k <<= ) {
for(int i = ; i < n; ++i) {
int j = sa[i] - k;
if(j < ) j += n;
tmp[c[rank[j]]++] = j;
}
int j = c[] = sa[tmp[]] = ;
for(int i = ; i < n; ++i) {
if(rank[tmp[i]] != rank[tmp[i - ]] || rank[tmp[i] + k] != rank[tmp[i - ] + k])
c[++j] = i;
sa[tmp[i]] = j;
}
memcpy(rank, sa, n * sizeof(int));
memcpy(sa, tmp, n * sizeof(int));
}
} void calheight() {
for(int i = , k = ; i < n; height[rank[i++]] = k) {
k -= (k > );
int j = sa[rank[i] - ];
while(s[i + k] == s[j + k]) ++k;
}
} struct Node {
int height, cnt;
Node(int height = , int cnt = ): height(height), cnt(cnt) {}
}; LL solve() {
LL ans = , sum = ;
stack<Node> stk; for(int i = ; i < n; ++i) {
int cnt = ;
while(!stk.empty() && stk.top().height >= height[i]) {
Node t = stk.top(); stk.pop();
cnt += t.cnt;
sum -= t.cnt * (t.height - k + 1LL);
}
if(height[i] >= k) {
cnt += (sa[i - ] < apart);
if(cnt) stk.push(Node(height[i], cnt));
sum += cnt * (height[i] - k + 1LL);
}
if(sa[i] > apart) ans += sum;
} while(!stk.empty()) stk.pop();
sum = ; for(int i = ; i < n; ++i) {
int cnt = ;
while(!stk.empty() && stk.top().height >= height[i]) {
Node t = stk.top(); stk.pop();
cnt += t.cnt;
sum -= t.cnt * (t.height - k + 1LL);
}
if(height[i] >= k) {
cnt += (sa[i - ] > apart);
stk.push(Node(height[i], cnt));
sum += cnt * (height[i] - k + 1LL);
}
if(sa[i] < apart) ans += sum;
} return ans;
} int main() {
while(scanf("%d", &k) != EOF && k) {
scanf("%s", s);
apart = strlen(s);
s[apart] = '$';
scanf("%s", s + apart + );
n = strlen(s) + ;
makesa();
calheight();
cout<<solve()<<endl;
}
}
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 后缀数组+并查集
后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求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 后缀数组+单调栈
题目链接 题意:求解两个字符串长度 大于等于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 ...
- POJ 3415 Common Substrings ——后缀数组
[题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #inclu ...
- POJ.3145.Common Substrings(后缀数组 倍增 单调栈)
题目链接 \(Description\) 求两个字符串长度不小于k的公共子串对数. \(Solution\) 求出ht[]后先减去k,这样对于两个后缀A',B',它们之间的贡献为min{ht(A)}( ...
- POJ 3415 Common Substrings(后缀数组 + 单调栈)题解
题意: 给两个串\(A.B\),问你长度\(>=k\)的有几对公共子串 思路: 先想一个朴素算法: 把\(B\)接在\(A\)后面,然后去跑后缀数组,得到\(height\)数组,那么直接\(r ...
随机推荐
- JavaScript常用DOM操作方法和函数
查找节点ocument.querySelector(selectors) //接受一个CSS选择器作为参数,返回第一个匹配该选择器的元素节点.document.querySelectorAll(sel ...
- 删除文件的第一列 -Linux
删除文件 text中第一列 方式一 awk '{$1="";print $0}' text 方式二 sed -e 's/[^ ]* //' text
- 解决jquey中当事件嵌套时,内层事件会执行多次的问题
出现情景:当内层事件需要外层事件触发后产生的一些值得时候 情景复现: <!DOCTYPE html> <html lang="en"> <head&g ...
- 使用EF Core的CodeFirt 出现的问题The specified framework version '2.1' could not be parsed
今天使用了一下EF Core的Code First,进行数据库迁移的的时候报错了: The specified framework version '2.1' could not be parsed ...
- Elasticsearch 数据查询
数据准备: PUT /shop { "settings": { "number_of_shards": 3, "number_of_replicas& ...
- apache上.htaccess转向nginx上配置.htaccess伪静态规则
nginx上配置.htaccess伪静态规则 在apache上.htaccess转向,只要apache编译的时候指明支持rewrite模块即可. 但是换到nginx上方法会有不同,有人说把.htacc ...
- HyperLedger Fabric 1.4 kafka生产环境部署(11.1)
11.1 Kafka模式简介 上一章介绍的Solo模式只存在一个排序(orderer)服务,是一种中心化结构,一旦排序(orderer)服务出现了问题,整个区块链网络将会崩溃,为了能在正式 ...
- RMI入门HelloWorld
java RMI(Remote Method Invocation)是一种基于java远程调用技术,是对RPC的java实现,可以在不同主机上进行通信与方法调用.PRC通信原理如图: 方法调用从客户对 ...
- Highchart 饼图联动
感觉好久没有更新博客了,最近一直忙着毕业论文,紧接着就开始搭建数据库,实在抽不出时间写. 正好趁着做数据库,写一写关于Highchart里两个饼图之间的互动. 用到的数据比较大,我也懒得修饰了,涉及到 ...
- jquery table 发送两次请求 解惑
版本1.10 以下链接为一个较低版本解决方案: http://blog.csdn.net/anmo/article/details/17083125 而我的情况有点作, 情况描述: 1,一个页面两个t ...