POJ 3415 后缀数组+单调栈
题目大意:
给定A,B两种字符串,问他们当中的长度大于k的公共子串的个数有多少个
这道题目本身理解不难,将两个字符串合并后求出它的后缀数组
然后利用后缀数组求解答案
这里一开始看题解说要用栈的思想,觉得很麻烦就不做了,后来在比赛中又遇到就后悔了,到今天看了很久才算看懂
首先建一个栈,从栈底到栈顶都保证是单调递增的
我们用一个tot记录当前栈中所有项和一个刚进入的子串匹配所能得到的总的子串的数目(当然前提是,当前进入的子串height值比栈顶还大,那么和栈中任意一个子串匹配都保持当前栈中记录的那时候入栈的height值)
但是若height不比栈顶大,说明从栈顶开始到刚好比它小的这一段tot有多加的部分,这部分就是height值多出来的那块,然后把这部分都视作height值为当前的height值,因为后面子串进入,它的height值总是取决于那段区间的最小值,所以不会产生影响,这样就可以把所有比当前height大的都弹出栈,这样就达到了O(n)的复杂度
这里用q[][]手写栈
q[i][0]表示栈中第i号元素记录时候的height值,q[i][1]表示在这个height值上覆盖了q[i][1]个子串
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
const int MAXN = *;
int sa[MAXN] , rank[MAXN] , height[MAXN];
int wa[MAXN] , wb[MAXN] , wsf[MAXN] , wv[MAXN];
int a[MAXN] , k;
char str1[MAXN] , str2[MAXN];
int q[MAXN][]; int cmp(int *r , int a , int b , int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
} void getSa(int *r , int *sa , int n , int m)
{
int *x = wa , *y = wb , *t;
for(int i= ; i<m ; i++) wsf[i]=;
for(int i= ; i<n ; i++) wsf[x[i]=r[i]]++;
for(int i= ; i<m ; i++) wsf[i]+=wsf[i-];
for(int i=n- ; i>= ; i--) sa[--wsf[x[i]]] = i; int i,j,p=;
for(j= ; p<n ; j*= , m=p)
{
for(p= , i=n-j ; i<n ; i++) y[p++] = i;
for(i= ; i<n ; i++) if(sa[i]>=j) y[p++] = sa[i]-j; for(i= ; i<n ; i++) wv[i]=x[y[i]];
for(i= ; i<m ; i++) wsf[i]=;
for(i= ; i<n ; i++) wsf[wv[i]]++;
for(i= ; i<m ; i++) wsf[i]+=wsf[i-];
for(i=n- ; i>= ; i--) sa[--wsf[wv[i]]] = y[i]; for(t=x , x=y , y=t , x[sa[]]= , p= , i=; i<n ; i++)
x[sa[i]] = cmp(y , sa[i-] , sa[i] , j)?p-:p++;
}
return ;
} void callHeight(int *r , int *sa , int n)
{
for(int i= ; i<=n ; i++) rank[sa[i]]=i;
int i , j , k=;
for(i= ; i<n ; height[rank[i++]]=k)
for(j=sa[rank[i]-] , k?k--: ; r[i+k]==r[j+k] ; k++) ;
return;
} ll solve(int len1 , int len2)
{
ll ans = ;
//B串中的子串不断匹配rank比其高的A子串
int top = ;
ll tot = , cnt = ;
for(int i= ; i<=len1+len2+ ; i++){
if(height[i]<k){
top = tot = ;
continue;
}
cnt = ;
if(sa[i-]<len1){
cnt ++;
tot += height[i]-k+;
}
while(top&&height[i]<=q[top][]){
tot -= q[top][]*(q[top][]-height[i]);
cnt += q[top][];
top--;
}
q[++top][] = height[i];
q[top][] = cnt;
if(sa[i]>len1) ans+=tot;
}
//A串中的子串不断匹配rank比其高的B子串
tot = top = ;
for(int i= ; i<=len1+len2+ ; i++){
if(height[i]<k){
top = tot = ;
continue;
}
cnt = ;
if(sa[i-]>len1){
cnt ++;
tot += height[i]-k+;
}
while(top&&height[i]<=q[top][]){
tot -= q[top][]*(q[top][]-height[i]);
cnt += q[top][];
top--;
}
q[++top][] = height[i];
q[top][] = cnt;
if(sa[i]<len1) ans+=tot;
}
return ans;
} int main()
{
// freopen("a.in" , "r" , stdin); while(scanf("%d" , &k) , k)
{
scanf("%s%s" , str1 , str2);
int len1 = strlen(str1) , len2 = strlen(str2);
for(int i= ; i<len1 ; i++) a[i] = (int)str1[i];
a[len1] = ;
for(int i= ; i<len2 ; i++) a[i+len1+] = (int)str2[i];
a[len1+len2+] = ; getSa(a , sa , len1+len2+ , );
callHeight(a , sa , len1+len2+); // for(int i=0 ; i<len1+len2+2 ; i++) cout<<"rank i: "<<i<<" "<<rank[i]<<endl;
// for(int i=1 ; i<len1+len2+2 ; i++) cout<<"xixi: "<<height[i]<<endl;
ll ans = solve(len1 , len2);
printf("%I64d\n" , ans);
}
return ;
}
POJ 3415 后缀数组+单调栈的更多相关文章
- 【BZOJ-3238】差异 后缀数组 + 单调栈
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1561 Solved: 734[Submit][Status] ...
- BZOJ_3879_SvT_后缀数组+单调栈
BZOJ_3879_SvT_后缀数组+单调栈 Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个 ...
- BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈
BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- 【BZOJ3879】SvT 后缀数组+单调栈
[BZOJ3879]SvT Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干 ...
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- poj 3415 Common Substrings(后缀数组+单调栈)
http://poj.org/problem?id=3415 Common Substrings Time Limit: 5000MS Memory Limit: 65536K Total Sub ...
- poj 3415 Common Substrings——后缀数组+单调栈
题目:http://poj.org/problem?id=3415 因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献. 一开始想 ...
随机推荐
- 字符编码 ASCII unicode UTF-8
字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(b ...
- (转)老生常谈-从输入url到页面展示到底发生了什么
刚开始写这篇文章还是挺纠结的,因为网上搜索"从输入url到页面展示到底发生了什么",你可以搜到一大堆的资料.而且面试这道题基本是必考题,二月份面试的时候,虽然知道这个过程发生了什么 ...
- Chrome浏览器调试移动端网页 chrome://inspect/#devices
我使用的是魅族(魅蓝NOTE6 ),电脑是win 7系统,以下几步就可以轻松使用浏览器内置的功能调试移动端网页了: 注意:谷歌浏览器需要先FQ,不然调试页面会空白或者报404错误,(不会FQ的可以联系 ...
- YII2.O学习三 前后台用户数据表分离
之前我们完成了Advanced 模板安装,也完成了安装adminlte 后台模板,这一步是针对前端和后台用户使用不同的数据库表来管理,做到前后台用户分离的效果: 复制一张user数据表并重命名为adm ...
- [【转】ubuntu 16.10 Server 安装及基本部署
一.Ubuntu Server 16.10 LTS 系统安装 Ubuntu 16.10 分为 桌面版 (desktop)和服务器版(Server).两者对于用户而言,最大的区别在于桌面版有图形操作界面 ...
- c/c++指针传参
首先要理解参数传递,参数传递分值传递,指针传递,引用传递.(就我自己理解,就是把实参对形参进行赋值) 值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单 ...
- P1189 SEARCH(逃跑的拉尔夫)
P1189 SEARCH 题目描述 年轻的拉尔夫开玩笑地从一个小镇上偷走了一辆车,但他没想到的是那辆车属于警察局,并且车上装有用于发射车子移动路线的装置. 那个装置太旧了,以至于只能发射关于那辆车的移 ...
- 涉及到大小变化,类似QScrollArea判断大小是否显示滚动条
涉及到大小变化,类似QScrollArea判断大小是否显示滚动条的情况要注意 这两个属性的设置:
- 用gradle编译任意结构的Android项目
## 需求 * 继续用`Eclipse`项目的结构,但是使用`gradle`编译,或者说任意的项目结构进行编译. ## 解决方案 1. Android studio的项目结构 1. Android S ...
- 【赛后补题】(HDU6228) Tree {2017-ACM/ICPC Shenyang Onsite}
这条题目当时卡了我们半天,于是成功打铁--今天回来一看,mmp,贪心思想怎么这么弱智.....(怪不得场上那么多人A了 题意分析 这里是原题: Tree Time Limit: 2000/1000 M ...