题目大意:

给定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 后缀数组+单调栈的更多相关文章

  1. 【BZOJ-3238】差异 后缀数组 + 单调栈

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1561  Solved: 734[Submit][Status] ...

  2. BZOJ_3879_SvT_后缀数组+单调栈

    BZOJ_3879_SvT_后缀数组+单调栈 Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个 ...

  3. BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  4. BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)

    BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...

  5. 【BZOJ3879】SvT 后缀数组+单调栈

    [BZOJ3879]SvT Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干 ...

  6. BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】

    题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...

  7. BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】

    题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...

  8. poj 3415 Common Substrings(后缀数组+单调栈)

    http://poj.org/problem?id=3415 Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Sub ...

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

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

随机推荐

  1. Angular简单总结

    AngularJS AngularJS四大特征 MVC模式 双向绑定 依赖注入 模块化设计 AngularJS 表达式 AngularJS 表达式写在双大括号内{{expression }},可以包含 ...

  2. 浅谈C#实现Web代理服务器的几大步骤

    代理服务程序是一种广泛使用的网络应用程序.代理程序的种类非常多,根据协议不同可以分成HTTP代理服务程序.FTP代理服务程序等,而运行代理服务程序的服务器也就相应称为HTTP代理服务器和FTP代理服务 ...

  3. Less Is More【少即是多】

    Less Is More Adults understand what it feels like to be flooed with objects. 成年人知道被物品淹没的感觉. Why do w ...

  4. c#vs连接SQL sever数据库入门操作

    对于需要连接数据库的项目,可以参考的简单初级代码.实现打开数据库,读入数据功能 using System; using System.Collections.Generic; using System ...

  5. 嵌入式框架Zorb Framework搭建四:状态机的实现

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

  6. HyperLedger Fabric 1.4 超级账本项目(5.4)

    超级账本(Hyperledger)项目分框架类和工具类两种项目,框架类有Hyperledger Burrow.Hyperledger Fabric.Hyperledger Indy.Hyperledg ...

  7. ionic 打包apk Failure [INSTALL_FAILED_USER_RESTRICTED: Install canceled by user]

    错误日志如下: Built the following apk(s): /Users/hongye0/Documents/project/haitoujiaApp/platforms/android/ ...

  8. React+DvaJS 之 hook 路由权限控制

    博客 学院 下载 GitChat TinyMind 论坛 APP 问答 商城 VIP 活动 招聘 ITeye 写博客 发Chat 登录注册 原 React+DvaJS 之 hook 路由权限控制 20 ...

  9. ABP框架设置默认语言

    在Global.asax文件中设置 private readonly IAbpWebLocalizationConfiguration _webLocalizationConfiguration; p ...

  10. jmeter之HTTP请求

    1.添加一个线程组:Test plan_添加_Threads(users)_线程组(右键操作),如下图: 2.添加一个HTTP请求:线程组_添加_sample_HTTP请求(右键操作),如下图: 3. ...