poj 3415 后缀数组+单调队列
来源:互联网 发布:数据恢复最好的软件 编辑:程序博客网 时间:2024/05/29 12:50
Common Substrings
Time Limit: 5000MS Memory Limit: 65536KTotal Submissions: 8106 Accepted: 2688
Description
A substring of a string T is defined as:
Given two strings A, B and one integer K, we defineS, a set of triples (i, j, k):
You are to give the value of |S| for specific A, B andK.
Input
The input file contains several blocks of data. For each block, the first line contains one integerK, followed by two lines containing strings A and B, respectively. The input file is ended byK=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
2aababaaabaabaa1xxxx0
Sample Output
225
Source
POJ Monthly--2007.10.06, wintokk
题意是求两个字符串长度>=K的公共子串有多少个。
先考虑怎么求解公共子串的问题。公共子串可以用后缀数组求,将两个字符串str1和str2合并为一个字符串,中间插入一个不会出现的字符做分割。得到后缀数组和高度数组,有了高度数组就可以求出任意两个后缀的lcp最长公共前缀值,lcp即为两个后缀之间height[i]的最小值。
回到这个问题上,假如两个分别属于str1和str2的后缀lcp为X (X>K), 那么就计数X-K+1个长度>=K的公共子串。那么答案就是每个属于str1和每个属于str2的lcp-K+1求和。
直接枚举要n^2logn复杂度(单次查询两个后缀lcp用rmq--logn复杂度)。任意两个后缀的lcp值取决于它们之间的最小值,直接枚举慢就慢在每两个后缀都要找一遍它们之间的最小值。利用最小值这个关键点,假如枚举以第i个lcp值为最小值的区间[l,r],那么ans+=(左边属于str1的后缀个数*右边属于str2+左边属于str2*右边属于str1)*(lcp-K+1)。而找到以某个值为最小值的区间用单调队列左右扫一遍O(n)就可以得到。
题意是求两个字符串长度>=K的公共子串有多少个。
先考虑怎么求解公共子串的问题。公共子串可以用后缀数组求,将两个字符串str1和str2合并为一个字符串,中间插入一个不会出现的字符做分割。得到后缀数组和高度数组,有了高度数组就可以求出任意两个后缀的lcp最长公共前缀值,lcp即为两个后缀之间height[i]的最小值。
回到这个问题上,假如两个分别属于str1和str2的后缀lcp为X (X>K), 那么就计数X-K+1个长度>=K的公共子串。那么答案就是每个属于str1和每个属于str2的lcp-K+1求和。
直接枚举要n^2logn复杂度(单次查询两个后缀lcp用rmq--logn复杂度)。任意两个后缀的lcp值取决于它们之间的最小值,直接枚举慢就慢在每两个后缀都要找一遍它们之间的最小值。利用最小值这个关键点,假如枚举以第i个lcp值为最小值的区间[l,r],那么ans+=(左边属于str1的后缀个数*右边属于str2+左边属于str2*右边属于str1)*(lcp-K+1)。而找到以某个值为最小值的区间用单调队列左右扫一遍O(n)就可以得到。
#include <iostream>#include <cstring>#include <cstdio>#include <vector>#include <algorithm>using namespace std;const int maxn=200005;int t1[maxn], t2[maxn], c[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 sa[], int rank[], int height[], 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++) rank[sa[i]]=i; for(i=0; i<n; i++){ if(k)k--; j=sa[rank[i]-1]; while(str[i+k]==str[j+k]) k++; height[rank[i]]=k; }}int n;int rank[maxn], height[maxn];char s[maxn];int r[maxn];int sa[maxn];int que[maxn], head,tail;int lb[maxn], rb[maxn];int sum[maxn]={0};int query(int l, int r){ return sum[r]-sum[l-1];}int main(){ int K; while(scanf("%d", &K)==1 &&K){ scanf("%s", s); int len=strlen(s); for(int i=0; i<len; i++) {r[i]=s[i];} scanf("%s", s); int len1=strlen(s); for(int i=0; i<len1; i++) r[len+1+i]=s[i]; n=len+1+len1; r[len]=1; r[n]=0; da(r,sa,rank, height, n,128); head=0,tail=-1; for(int i=1; i<=n; i++){ while(tail+1!=head && height[que[tail]]>height[i]) tail--; if(tail+1!=head) lb[i]=que[tail]+1; else lb[i]=1; que[++tail]=i; } head=0, tail=-1; for(int i=n; i>=1; i--){ while(tail+1!=head && height[que[tail]]>=height[i]) tail--; if(tail+1!=head) rb[i]=que[tail]-1; else rb[i]=n; que[++tail]=i; } memset(sum, 0, sizeof(sum)); //前缀和维护区间内属于str1的后缀个数 for(int i=1; i<=n; i++){ if(sa[i]<len) sum[i]++; sum[i]+=sum[i-1]; } long long ans=0;//注意答案可能大于int for(int i=2; i<=n; i++){ if(height[i]<K) continue; int l=lb[i]-1, r=rb[i]; int ltot=i-l, rtot=r-i+1; ans+=(long long)query(l, i-1)*(rtot-query(i, r))*(height[i]-K+1); ans+=(long long)(ltot-query(l,i-1))*query(i, r)*(height[i]-K+1); } printf("%lld\n", ans); } return 0;}
0 0
- poj 3415 后缀数组+单调队列
- poj Common Substrings(后缀数组&单调队列)
- POJ 3415 后缀数组 + 单调栈
- poj 3415 后缀数组+单调栈||后缀自动机
- poj3415 Common Substrings (后缀数组+单调队列)
- POJ 3415 Common Substrings(后缀数组+单调栈)
- POJ 3415 Common Substrings 后缀数组 计数 单调栈优化
- 【POJ】3415 Common Substrings 【后缀数组+单调栈】
- POJ 3415 Common Substrings 后缀数组 + 单调栈维护
- poj 3415 Common Substrings(后缀数组+单调栈)
- POJ 3415:Common Substrings 后缀数组+单调栈
- POJ 3415 Common Substrings(后缀数组+单调栈)
- [POJ 3415] Common Substrings (后缀数组+单调栈优化)
- poj 3415 Common Substrings (后缀数组+单调栈)
- POJ - 3415 Common Substrings 后缀数组+单调栈+前缀和
- POJ 3415 Common Substrings <后缀数组+单调栈>
- POJ-3415-Common Substrings(后缀数组+单调栈)
- poj 3415 Common Substrings(后缀数组+单调栈+dp)
- PostGIS入门
- hdu5148 树形dp,分组背包
- 第十周——面向对象——继承与派生——项目二(2)职员薪水类
- 《控制方法C语言实现》拓展话题讲解系列 第二节
- 【数据结构】实现顺序表(c++)
- poj 3415 后缀数组+单调队列
- dlopen动态链接库操作
- 自动化运维工具---saltstack
- 友盟分享,设置分享平台问题,添加豆瓣等等。
- GDB Manual
- nginx配置详解
- 关于MongoDB你需要知道的几件事
- Leetcode Pascal's Triangle II
- java的数据类型