Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 9414   Accepted: 3123

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

Sample Input

  1. 2
  2. aababaa
  3. abaabaa
  4. 1
  5. xx
  6. xx
  7. 0

Sample Output

  1. 22

5

题意:给你2个字符串,让你分别在两个字符串中找到一个相同的子串,并且这两个相同串的长度要大于等于k,求这样的子串个数。

思路:这题思路不好想啊。我们知道,一个字符串的子串可以由母串的一个后缀的前缀表示,所以题目就变为求A中所有后缀的前缀和B中所有后缀的前缀公共前缀长度大于等于k的对数。我们可以把两个串连接起来,并且在两个串的中间插入一个以前没有出现过的字符(注意:这个字符的大小不能是0,即不能和最后一个我们自己添加的字符的大小相同,不然会错 = =),然后先求出sa[],height[]。按height[]值分组后,接下来的工作便是快速的统计每组中后缀之间的最长公共前缀之和。扫描一遍,每遇到一个B的后缀就统计与前面的A 的后缀能产生多少个长度不小于k 的公共子串,这里A 的后缀需要用一个单调的栈来高效的维护,然后对A也这样做一次。

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. #include<math.h>
  6. #include<vector>
  7. #include<map>
  8. #include<set>
  9. #include<string>
  10. #include<bitset>
  11. #include<algorithm>
  12. using namespace std;
  13. #define lson th<<1
  14. #define rson th<<1|1
  15. typedef long long ll;
  16. typedef long double ldb;
  17. #define inf 99999999
  18. #define pi acos(-1.0)
  19. #define M 100050
  20. #define maxn 200050
  21. char s1[M],s2[M];
  22. int sa[maxn],a[maxn];
  23. int wa[maxn],wb[maxn],wv[maxn],we[maxn];
  24. int rk[maxn],height[maxn];
  25. int cmp(int *r,int a,int b,int l){
  26. return r[a]==r[b]&&r[a+l]==r[b+l];
  27. }
  28. void build_sa(int *r,int n,int m)
  29. {
  30. int i,j,p,*x=wa,*y=wb,*t;
  31. for(i=0;i<m;i++)we[i]=0;
  32. for(i=0;i<n;i++)we[x[i]=r[i]]++;
  33. for(i=1;i<m;i++)we[i]+=we[i-1];
  34. for(i=n-1;i>=0;i--)sa[--we[x[i]]]=i;
  35. for(j=1,p=1;p<n;j*=2,m=p){
  36. for(p=0,i=n-j;i<n;i++)y[p++]=i;
  37. for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
  38. for(i=0;i<n;i++)wv[i]=x[y[i]];
  39. for(i=0;i<m;i++)we[i]=0;
  40. for(i=0;i<n;i++)we[wv[i]]++;
  41. for(i=1;i<m;i++)we[i]+=we[i-1];
  42. for(i=n-1;i>=0;i--)sa[--we[wv[i]]]=y[i];
  43. for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
  44. x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
  45. }
  46. }
  47. void calheight(int *r,int n)
  48. {
  49. int i,j,k=0;
  50. for(i=1;i<=n;i++)rk[sa[i]]=i;
  51. for(i=0;i<n;height[rk[i++] ]=k){
  52. for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
  53. }
  54. }
  55. int q[111111][3]; //0表示高度,1表示宽度,2表示时间
  56. int main()
  57. {
  58. int n,m,i,j,k;
  59. int front,rear,len1,len2;
  60. ll sum,kuan,tot; //sum表示最后的答案,kuan表示单调队列里面每一个元素的宽度
  61. while(scanf("%d",&k)!=EOF && k!=0)
  62. {
  63. scanf("%s%s",s1,s2);
  64. n=0;
  65. len1=strlen(s1);
  66. len2=strlen(s2);
  67. for(i=0;i<len1;i++){
  68. a[n++]=s1[i]-'a'+98;
  69. }
  70. a[n++]=1;
  71. for(i=0;i<len2;i++){
  72. a[n++]=s2[i]-'a'+98;
  73. }
  74. a[n]=0;
  75. build_sa(a,n+1,130);
  76. calheight(a,n);
  77. sum=0;
  78. for(i=1;i<=n;i++){
  79. if(height[i]<k){
  80. front=1,rear=0;
  81. tot=0; //tot表示所有面积和
  82. continue;
  83. }
  84. kuan=0;
  85. while(front<=rear && q[rear][0]>=height[i]){
  86. kuan+=q[rear][1];
  87. tot-=q[rear][1]*(q[rear][0]-height[i]);
  88. rear--;
  89. }
  90. if(sa[i-1]<len1){
  91. kuan++;
  92. tot+=height[i]-k+1;
  93. }
  94. rear++;
  95. q[rear][0]=height[i];q[rear][1]=kuan;
  96. if(sa[i]>len1){
  97. sum+=tot;
  98. }
  99. }
  100. for(i=1;i<=n;i++){
  101. if(height[i]<k){
  102. front=1,rear=0;
  103. tot=0; //tot表示所有面积和
  104. continue;
  105. }
  106. kuan=0;
  107. while(front<=rear && q[rear][0]>=height[i]){
  108. kuan+=q[rear][1];
  109. tot-=q[rear][1]*(q[rear][0]-height[i]);
  110. rear--;
  111. }
  112. if(sa[i-1]>len1){
  113. kuan++;
  114. tot+=height[i]-k+1;
  115. }
  116. rear++;
  117. q[rear][0]=height[i];q[rear][1]=kuan;
  118. if(sa[i]<len1){
  119. sum+=tot;
  120. }
  121. }
  122. printf("%lld\n",sum);
  123. }
  124. return 0;
  125. }

poj3415 Common Substrings (后缀数组+单调队列)的更多相关文章

  1. POJ3415 Common Substrings —— 后缀数组 + 单调栈 公共子串个数

    题目链接:https://vjudge.net/problem/POJ-3415 Common Substrings Time Limit: 5000MS   Memory Limit: 65536K ...

  2. POJ3415 Common Substrings(后缀数组 单调栈)

    借用罗穗骞论文中的讲解: 计算A 的所有后缀和B 的所有后缀之间的最长公共前缀的长度,把最长公共前缀长度不小于k 的部分全部加起来.先将两个字符串连起来,中间用一个没有出现过的字符隔开.按height ...

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

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

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

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

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

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

  6. hihoCoder 1403 后缀数组一·重复旋律(后缀数组+单调队列)

    #1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...

  7. BZOJ_4698_Sdoi2008 Sandy的卡片_后缀数组+单调队列+双指针

    BZOJ_4698_Sdoi2008 Sandy的卡片_后缀数组 Description Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是 ...

  8. POJ 3261 Milk Patterns(后缀数组+单调队列)

    题意 找出出现k次的可重叠的最长子串的长度 题解 用后缀数组. 然后求出heigth数组. 跑单调队列就行了.找出每k个数中最小的数的最大值.就是个滑动窗口啊 (不知道为什么有人写二分,其实写啥都差不 ...

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

随机推荐

  1. LeetCode144 二叉树的前序遍历

    给定一个二叉树,返回它的 前序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? /** * Defin ...

  2. PAT甲级 1155 Heap Paths (30分) 堆模拟

    题意分析: 给出一个1000以内的整数N,以及N个整数,并且这N个数是按照完全二叉树的层序遍历输出的序列,输出所有的整条的先序遍历的序列(根 右 左),以及判断整棵树是否是符合堆排序的规则(判断是大顶 ...

  3. Docker学习笔记之查看Docker

    命令: 使用history命令查看镜像历史 使用cp命令复制容器中的文件到主机 使用commit命令把修改过的容器创建为镜像 使用diff命令检查容器文件的修改 使用inspect命令查看容器/镜像详 ...

  4. Mongodb 安装和副本集集群搭建

    通用步骤,适用于所有你需要用的软件. 总结为5大步骤: 找到官网-->下载包-->解压-->修改配置-->启动 不懂的,首选官网api,次选百度 1.安装mongodb mon ...

  5. leetcode 470. 用 Rand7() 实现 Rand10() (数学,优化策略)

    题目链接 https://leetcode-cn.com/problems/implement-rand10-using-rand7/ 题意: 给定一个rand7()的生成器,求解如何产生一个rand ...

  6. leetcode 31. Next Permutation (下一个排列,模拟,二分查找)

    题目链接 31. Next Permutation 题意 给定一段排列,输出其升序相邻的下一段排列.比如[1,3,2]的下一段排列为[2,1,3]. 注意排列呈环形,即[3,2,1]的下一段排列为[1 ...

  7. 记一道C语言编程题(C语言学习笔记)

    题目如下 解答如下 #include <stdio.h> #include<math.h> double Mysqrt(double n) { return sqrt(n); ...

  8. oracle创建恢复编录(recovery catalog)

    1.在要作为恢复编录的数据库创建用户 create user rman identified by oracle default tablespace system temporary TABLESP ...

  9. SAP中的密码输入框

    在SAP中的密码输入框,可分为两种情况: 1.用selection语句书写的选择屏幕上的密码输入框 实现的方式就是在AT SELECTION-SCREEN OUTPUT事件中写入如下代码: LOOP ...

  10. 爬虫学习(二)requests模块的使用

    一.requests的概述 requests模块是用于发送网络请求,返回响应数据.底层实现是urllib,而且简单易用,在python2.python3中通用,能够自动帮助我们解压(gzip压缩的等) ...