HDU 6194【后缀数组】
题目链接【http://acm.hdu.edu.cn/showproblem.php?pid=6194】
题意:
给你一个长度不大于1e5的字符串,然后然你判断其子串严格出现k次的子串个数。
题解:
后缀数组 + RMQ。首先说一下后缀数组里面的三个数组的作用:
sa[i] 数组 : 排名为i的后缀是[sa[i] - end];
Rank[i] 数组 : 后缀为[i - end]的排名是Rank[i]
height[i] 数组 : 排名为i的后缀和排名为i - 1的后缀的最长前缀。
这里主要用到了height数组,首先我们考虑k == 1的情况,tmp = max(height[i], height[i + 1]),tmp表示排名为i的串和排名为i-1的串的公共前缀及排名为i+1的串和排名为i的串的公共前缀的最大值,那么可以知道排名为i的串中一共有len[i](排名为i的串的长度) - tmp个。
当k>1的时候,我们就要维护height的区间最小值了。从排名为k的串开始枚举(排名在k之前的串肯定出现不了k次),我们维护
int tmp = RMQMI(i - lenk + 2, i);
int x = max(height[i + 1], height[i - lenk + 1]);
if(tmp - x > 0) ans += tmp - x;
tmp,表示串i-lenk+1,到串i的公共不部分,表示公共部分的串出现了k次或者以上,再判断max(height[i + 1], height[i - lenk + 1]);,答案即为 tmp - x。
- #include<bits/stdc++.h>
- const int maxn = 1e6 + 5;
- using namespace std;
- char s[maxn];
- int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
- int T, lenk;
- void build_sa(int m)
- {
- int *x = t, *y = t2;
- for(int i = 0; i < m; i++) c[i] = 0;
- for(int i = 0; i < n; i++) c[x[i] = s[i]]++;
- for(int i = 1; i < m; i++) c[i] += c[i - 1];
- for(int i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
- for(int k = 1; k <= n; k <<= 1)
- {
- int p = 0;
- for(int i = n - k; i < n; i++) y[p++] = i;
- for(int i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
- for(int i = 0; i < m; i++) c[i] = 0;
- for(int i = 0; i < n; i++) c[x[y[i]]]++;
- for(int i = 0; i < m; i++) c[i] += c[i - 1];
- for(int i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
- swap(x, y);
- p = 1;
- x[sa[0]] = 0;
- for(int i = 1; i < n; i++)
- x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
- if(p >= n) break;
- m = p;
- }
- }
- int cmp_suffix(char* pattern, int p, int m)
- {
- return strncmp(pattern, s + sa[p], m);
- }
- int Rank[maxn], height[maxn];
- void getHeight()
- {
- int i, j, k = 0;
- 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(s[i + k] == s[j + k]) k++;
- height[Rank[i]] = k;
- }
- height[0] = 0;
- }
- int mi[maxn][20], lmt[maxn];
- void InitRMQ()
- {
- int N = n - 1;
- lmt[0] = -1;
- for(int i = 1; i <= N; i++)
- {
- lmt[i] = ((i & (i - 1)) == 0) ? lmt[i - 1] + 1 : lmt[i - 1];
- mi[i][0] = height[i];
- }
- for(int j = 1; j <= lmt[N]; j++)
- {
- for(int i = 1; i + (1 << j) - 1 <= N; i++)
- mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);
- }
- }
- int RMQMI(int x, int y)
- {
- int k = lmt[y - x + 1];
- return min(mi[x][k], mi[y - (1 << k) + 1][k]);
- }
- int main ()
- {
- scanf("%d", &T);
- while(T--)
- {
- scanf("%d %s", &lenk, s);
- n = strlen(s) + 1;
- build_sa(127);
- for(int i = 1; i <= n; i++) height[i] = 0;
- getHeight();
- int ans = 0;
- if(lenk == 1)
- {
- for(int i = 1; i < n; i++)
- {
- int len = n - sa[i] - 1;
- int tmp = max(height[i], height[i + 1]);
- if(len - tmp > 0) ans += len - tmp;
- }
- }
- else
- {
- InitRMQ();
- for(int i = lenk; i < n; i++)
- {
- int tmp = RMQMI(i - lenk + 2, i);
- int x = max(height[i + 1], height[i - lenk + 1]);
- if(tmp - x > 0) ans += tmp - x;
- }
- }
- printf("%d\n", ans);
- }
- return 0;
- }
HDU 6194【后缀数组】的更多相关文章
- HDU 6194 后缀数组
string string string Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- hdu 3948 后缀数组
The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (J ...
- HDU - 3948 后缀数组+Manacher
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3948 题意:给定一个字符串,求字符串本质不同的回文子串个数. 思路:主要参考该篇解题报告 先按照man ...
- HDU 5769 后缀数组
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5769 [2016多校contest-4] 题意:给定一个字符,还有一个字符串,问这个字符串存在多少个不 ...
- hdu 2459 (后缀数组+RMQ)
题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...
- hdu 3518(后缀数组)
题意:容易理解... 分析:这是我做的后缀数组第一题,做这个题只需要知道后缀数组中height数组代表的是什么就差不多会做了,height[i]表示排名第i的后缀与排名第i-1的后缀的最长公共前缀,然 ...
- hdu 5442 (后缀数组)
稍微学习了下第一次用后缀数组- - , 强行凑出答案 , 感觉现在最大的问题是很多算法都不知道 ,导致有的题一点头绪都没有(就像本题). /*推荐 <后缀数组——处理字符串的有力工具>— ...
- HDU 5558 后缀数组
思路: 这是一个错误的思路, 因为数据水才过= = 首先求出来后缀数组 把rank插到set里 每回差i两边离i近的rank值,更新 如果LCP相同,暴力左(右)继续更新sa的最小值 //By Sir ...
- HDU 4691 后缀数组+RMQ
思路: 求一发后缀数组,求个LCP 就好了 注意数字有可能不只一位 (样例2) //By SiriusRen #include <bits/stdc++.h> using namespac ...
- K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)
大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...
随机推荐
- 如何在AngularJS渲染后再加载JS
http://www.itnose.net/detail/6100484.html app.directive('repeatDone', function () { return function ...
- MongoDB常用方法
一.查询 find方法 db.collection_name.find(); 查询所有的结果: select * from users; db.users.find(); 指定返回那些列(键): se ...
- Java实现链式存储的二叉树
二叉树的定义: 二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的.分别称作这个根的左子树和右子树的二叉树组成. 二叉树的遍历方式主要 ...
- 初学者必看:.NET 中的静态与非静态的异同
对于初学者来说,.NET 的静态和非静态一直比较难掌握,这里做一个总结,介绍静态类和普通类,静态方法和实例方法,静态构造函数和实例构造函数,静态字段和非静态字段的区别. 静态类 vs 普通类 静态类与 ...
- web上下文监听器ServletContextListener
1 package com.liveyc.common.listener; import javax.servlet.ServletContextEvent; import javax.servlet ...
- 59、有用过with statement吗?它的好处是什么?
python中的with语句是用来干嘛的?有什么作用? with语句的作用是通过某种方式简化异常处理,它是所谓的上下文管理器的一种 用法举例如下: with open('output.txt', 'w ...
- Django之前端插件定制之表头
什么是插件? 插件只是辅助,是开发过程中的一个阶段.一般项目一期会用各种插件,迅速将功能.界面搭出来,二期时就改成自己的代码了.大点的公司都有自己的js库,自己开发类似jquery的库. 那接下来就写 ...
- cookie、localstroage与sessionstroage的一些优缺点
1. Cookie 在前端开发中,尽量少用cooie,原因: (1) cookie限制大小,约4k左右,不适合存储业务数据,尤其是数据量较大的值: (2) cookie会每次随http请 ...
- 解决Chrome下表单自动填充后背景色为黄色
Chrome浏览器在表单自动填充后会显示黄色背景,这是Chrome的私有属性导致,对于有洁癖的人来讲,是不喜欢的,我们可以手动去掉. 代码如下: input:-webkit-autofill { -w ...
- 牛B的日本精神
在汤森路透评选出的<2015全球创新企业百强>榜单里,日本以40家高居榜首,力压美国的35家.而中国内地无一入围. 在中国媒体上,我们见到的日本是“失去的20年”,经济衰退.创新能力丧 ...