Description

A substring of a string T is defined as:

T(ik)=TiTi+1...Ti+k-1, 1≤ii+k-1≤|T|.

Given two strings AB and one integer K, we define S, a set of triples (ijk):

S = {(ijk) | kKA(ik)=B(jk)}.

You are to give the value of |S| for specific AB 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(后缀数组)的更多相关文章

  1. poj 3415 Common Substrings —— 后缀数组+单调栈

    题目:http://poj.org/problem?id=3415 先用后缀数组处理出 ht[i]: 用单调栈维护当前位置 ht[i] 对之前的 ht[j] 取 min 的结果,也就是当前的后缀与之前 ...

  2. poj 3415 Common Substrings——后缀数组+单调栈

    题目:http://poj.org/problem?id=3415 因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献. 一开始想 ...

  3. POJ 3415 Common Substrings 后缀数组+并查集

    后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i ...

  4. 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 ...

  5. poj 3415 Common Substrings 后缀数组+单调栈

    题目链接 题意:求解两个字符串长度 大于等于k的所有相同子串对有多少个,子串可以相同,只要位置不同即可:两个字符串的长度不超过1e5; 如 s1 = "xx" 和 s2 = &qu ...

  6. poj 3415 Common Substrings - 后缀数组 - 二分答案 - 单调栈

    题目传送门 传送点I 传送点II 题目大意 给定串$A, B$,求$A$和$B$长度大于等于$k$的公共子串的数量. 根据常用套路,用一个奇怪的字符把$A$,$B$连接起来,然后二分答案,然后按mid ...

  7. 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 ...

  8. POJ 3415 Common Substrings ——后缀数组

    [题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #inclu ...

  9. POJ.3145.Common Substrings(后缀数组 倍增 单调栈)

    题目链接 \(Description\) 求两个字符串长度不小于k的公共子串对数. \(Solution\) 求出ht[]后先减去k,这样对于两个后缀A',B',它们之间的贡献为min{ht(A)}( ...

  10. POJ 3415 Common Substrings(后缀数组 + 单调栈)题解

    题意: 给两个串\(A.B\),问你长度\(>=k\)的有几对公共子串 思路: 先想一个朴素算法: 把\(B\)接在\(A\)后面,然后去跑后缀数组,得到\(height\)数组,那么直接\(r ...

随机推荐

  1. BZOJ 3771: Triple(生成函数 FFT)

    Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 911  Solved: 528[Submit][Status][Discuss] Description ...

  2. Django学习笔记3-静态文件调用

    1.settings.py 静态文件相关示例代码及说明: # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.c ...

  3. IO流,Properties基本功能和遍历

    import java.util.Enumeration; import java.util.Iterator; import java.util.Properties; import java.ut ...

  4. company.scss

    .company{ @extend .layout; width:100%; h3{ display: block; margin: 20px 0; text-align: left; } .comp ...

  5. 网站http配置https -- 阿里云 nginx

    通过阿里云领取免费证书可将网站配置为https 步骤为下: 登陆阿里云点击sll证书,然后点击购买证书 选择免费的 然后立即购买 购买后会让你填写一些域名信息 然后提交签发证书 签发后点击下方下载 选 ...

  6. thinkphp5.0上对redis的具体操作

    一.环境搭建 首先先安装composer.thinkphp5.0版本.和redis的windows版本的redis程序或者linux版本的redis程序,linux安装教程: https://www. ...

  7. angular2路由之routerLinkActive指令

    angular2的routerLinkActive指令在路由激活时添加样式class .red{  color: red;}    <a routerLink="/user/login ...

  8. Dubbo client 启动报错:No provider available for the service use dubbo version 2.5.3

    1.异常 java.lang.IllegalStateException: Failed to check the status of the service org.ko.server.servic ...

  9. Python学习手册之正则表达式和元字符

    在上一篇文章中,我们介绍了 Python 的数据封装.类方法.静态方法和属性函数,现在我们介绍 Python 的正则表达式和元字符.查看上一篇文章请点击:https://www.cnblogs.com ...

  10. hadoop 1.x 集群环境的搭建

    本文主要以个人工作学习总结为主,同时也为了方便更多的兴趣爱好者参与学习交流,现将具体的搭建步骤分享如下: 一.基础环境 1.1 jdk的安装与配置 Hadoop是用Java开发的,Hadoop的编译及 ...