题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194
找到一个字符串中恰好出现k次的子串的数目。


思路:

计算出height数组,根据height数组进行操作,因为子串恰好出现k次,很显然需要找到一个长度为k-1的区间,这个区间要满足区间两边的height都比区间内的最小值要小,这样利用单调栈求出每个height左右两边第一个比height小的位置,如果左右两个位置包括的区间长度正好为k-1,那么所枚举的这个height减去左右两边height的最大值就是需要统计的恰好出现k次的子串数目。
有两点需要注意,第一是需要单独考虑k==1的情况,第二是对于同一段的相同数字,比如:1,2,3,2,1;此时两个2的左右区间都相同,只需要考虑一个2,这在求利用单调栈时标记一下即可。


代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;int n;
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 build(int a[],int sa[],int rk[],int height[],int n,int m) {n++;int i, j, p, *x = t1, *y = t2;//第一轮基数排序,如果s的最大值很大,可改为快速排序for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = a[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;//直接利用sa数组排序第二关键字for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;//这样数组y保存的就是按照第二关键字排序的结果//基数排序第一关键字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];//根据sa和x数组计算新的x数组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++)rk[sa[i]] = i;for(i = 0; i < n; i++){if(k)   k--;j = sa[rk[i]-1];while(a[i+k] == a[j+k])k++;height[rk[i]] = k;}
}int sa[MAXN], height[MAXN], rk[MAXN], a[MAXN];
int L[MAXN], R[MAXN];
char s[MAXN];
bool vis[MAXN];
stack <int> sta;int main(){//freopen("in.txt", "r", stdin);int T;scanf("%d", &T);while (T--) {int k;scanf("%d%s", &k, s);n = strlen(s);for (int i = 0; i < n; i++)a[i] = s[i] - 'a' + 1;a[n] = 0;build(a, sa, rk, height, n, 27);height[0] = height[n + 1] = 0;LL ans = 0;if (k == 1) {for (int i = 1; i <= n; i++) {int tmp = n - sa[i] - max(height[i], height[i + 1]);if (tmp > 0) ans += tmp;}}else {while (!sta.empty()) sta.pop();for (int i = 1; i <= n; i++) {vis[i] = true;while (!sta.empty() && height[sta.top()] >= height[i]) sta.pop();if (sta.empty()) L[i] = 0;else L[i] = sta.top();sta.push(i);}while (!sta.empty()) sta.pop();for (int i = n; i >= 1; i--) {while (!sta.empty() && height[sta.top()] >= height[i]) {if (height[sta.top()] == height[i]) vis[sta.top()] = false;sta.pop();}if (sta.empty()) R[i] = n + 1;else R[i] = sta.top();sta.push(i);}for (int i = 1; i <= n; i++) {if (!vis[i]) continue;if (R[i] - L[i] != k) continue;ans += (LL)(height[i] - max(height[L[i]], height[R[i]]));}}printf("%I64d\n", ans);}return 0;
}

HDU 6194 后缀数组+单调栈相关推荐

  1. [Ahoi2013]差异[后缀数组+单调栈]

    链接 解题思路:很明显前面∑1<=i<j<=nlen(Ti)+len(Tj)\sum_{1<=i<j<=n}len(T_i)+len(T_j)∑1<=i< ...

  2. [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】

    题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...

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

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

  4. POJ - 3415 Common Substrings(后缀数组+单调栈)

    题目链接:点击查看 题目大意:给出两个字符串,再给出一个k,问两个字符串中长度大于等于k的公共子串有多少个(种类可重复) 题目分析:因为涉及到了子串问题,先用后缀数组跑出height数组来,接下来如果 ...

  5. [bzoj3238]差异(后缀数组+单调栈)

    显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是 ...

  6. [BZOJ3238][AHOI2013]差异 [后缀数组+单调栈]

    题目地址 - GO-> 题目大意: 给定一个长度为 nn 的字符串SS,令TiTi表示它从第ii个字符开始的后缀,求以下这个式子的值: ∑1≤i<j≤nlen(Ti)+len(Tj)−2× ...

  7. 【BZOJ3879】SvT,后缀数组+单调栈维护sum

    Time:2016.08.15 Author:xiaoyimi 转载注明出处谢谢 如果有不明白的地方可以在下面评论问我 传送门 思路: 建立后缀数组求出Height 如果说对每次询问暴力求LCP累加的 ...

  8. POJ 3415 后缀数组+单调栈

    题目大意: 给定A,B两种字符串,问他们当中的长度大于k的公共子串的个数有多少个 这道题目本身理解不难,将两个字符串合并后求出它的后缀数组 然后利用后缀数组求解答案 这里一开始看题解说要用栈的思想,觉 ...

  9. bzoj 3238: [Ahoi2013]差异(后缀数组+单调栈)

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 3443  Solved: 1562 [Submit][Stat ...

最新文章

  1. 测试香港服务器访问速度的方法
  2. Spring Boot 多模块与 Maven 私有仓库
  3. MySQL数据库备份和还原的常用命令
  4. 服务器内存傲腾基本参数信息,服务器加傲腾内存
  5. 详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
  6. Python的魔法方法 .
  7. DB2操作指南及命令大全word版
  8. 字符串用法大全(源码解析,建议收藏!)
  9. 图像分类python代码_20行代码:Serverless架构下用Python轻松搞定图像分类
  10. JAVA 实现《中国象棋》游戏
  11. phpdesigner 配置SVN
  12. matlab怎么表示x的平方,用matlab算多项式x平方
  13. Floyd最短路径算法(来自微信公众号“算法爱好者”改编)
  14. c语言创建一个bat文件内容,基础教程:如何创建批处理文件
  15. Socket:由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作
  16. Word WPS 标题二编号未跟随一级标题
  17. 一家化工厂的数字化三级跳 | 产研案例
  18. 网上书店(基于JavaWeb和Mysql)项目
  19. codeforce 141A
  20. Java面向对象之线程相关概念 和 线程基本使用

热门文章

  1. 历届上海国际电影节获奖名单
  2. JAVA开发基础之使用IDEA导出JAR包
  3. python Xarray处理设置2维数组作为coordinates
  4. 罗塞塔石碑1141问题
  5. overleaf 插入图片_Overleaf手册(三)--图片
  6. 关于微信分享 签名不一致的问题解决
  7. Oracle数据库 SQL语句总结大赏
  8. 学习ARM开发(10)
  9. python【模块】xml.etree.ElementTree 解析 xml
  10. oj2448: 分离正整数中的各位数