HDU 6194 string string string 后缀数组 + RMQ(线段树)
传送门:HDU6194
题意:问给定字符串中有多少种出现k次的子串。
思路:首先想到后缀数组经典问题,求出现不少于k次的子串的最大长度,类似的这题肯定就是在height数组上搞事情啦。
将height数组每相邻k - 1个一组,这k - 1个height[i]中最小的那个设为tmp,就表示这排名相邻的k个后缀的最长公共前缀(设为s)长度为tmp,可以得出s出现了至少k次,那么长度为tmp - 1,tmp - 2 ...1的s的前缀必定也出现了至少K次,要确定这些串是否严格出现了k次,还要判断这相邻k - 1个height的前一个height值和后一个height值,分别设为height[i] 和 height[j],则长度为 1 -- max(height[i], height[j]) 的s的前缀出现了至少k + 1次,因此要去掉这部分。
对于每相邻k - 1个一组的height都求一下对答案的贡献就好了。
至于求相邻k - 1个height的最小值, 那就各显神通了,什么ST表,线段树都可以啦(刚刚想起来因为是连续求最小值,单调队列(滑动窗口)好像也可以)。
以上办法只能解决k >= 2的问题,k == 1的时候是无法解决的(可以自己想想height数组的定义),比赛的时候蒟弱就是卡死在这了。。两个小时愣是没想出来k == 1该怎么解。。
赛后突然灵光一现,我们只要求出所有不同子串的个数,然后减去那些出现大于等于两次不就行了么。。前几天还刚做过后缀数组求不同子串个数(传送门:点击打开链接)。。也是后缀经典用法,不多说了,问题是怎么减去出现大于等于两次的串的个数,height数组啊!height数组啊!height数组啊!(注意不要减重了)
代码:
#include<bits/stdc++.h>
#define ll long long
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define inf 0x3f3f3f3f
using namespace std;
const int MAXN = 100010;
int t1[MAXN], t2[MAXN], c[MAXN];
int ra[MAXN], height[MAXN];
int sa[MAXN];
char str[MAXN];
int n;
bool cmp(int *r, int a, int b, int l)
{ return r[a]==r[b]&&r[a+l]==r[b+l];
} void da(char str[], int sa[], int ra[], 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++) ra[sa[i]] = i; for(i = 0; i < n; i++) { if(k) k--; j = sa[ra[i]-1]; while(str[i+k]==str[j+k]) k++; height[ra[i]] = k; }
}
int num[MAXN << 2];
void build(int l, int r, int rt)
{if(l == r){num[rt] = height[l];return ;}int mid = (l + r) >> 1;build(lson);build(rson);num[rt] = min(num[rt << 1], num[rt << 1 | 1]);
}
int query(int L, int R, int l, int r, int rt)
{if(L <= l && r <= R){return num[rt];}int mid = (l + r) >> 1, ans = inf;if(L <= mid)ans = min(ans, query(L, R, lson));if(R > mid)ans = min(ans, query(L, R, rson));return ans;
}
int main()
{//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);int n,k;int T;cin>>T;while(T--){scanf("%d",&k);scanf(" %s", str);n=strlen(str);da(str, sa, ra, height, n, 128);build(1, n, 1);int last = 2;ll ans = 0;if(k == 1){//ans = 1ll * (n + 1) * n / 2;for(int i = 1; i <= n; i++){ans += n - sa[i] - height[i];if(height[i] > height[i - 1])ans -= (height[i] - height[i - 1]);}cout << ans << endl;continue;}for(int i = 2; i <= n; i++){if(i - k + 2 < 2) continue;int tmp = query(i - k + 2, i, 1, n, 1), tmp2;if(i - k + 1 < 2) tmp2 = 0;else tmp2 = height[i - k + 1];if(i + 1 <= n)tmp2 = max(tmp2, height[i + 1]);if(tmp > tmp2)ans += tmp - tmp2;}printf("%lld\n",ans);}return 0;
}
HDU 6194 string string string 后缀数组 + RMQ(线段树)相关推荐
- HDU - 4552 怪盗基德的挑战书(后缀数组+RMQ/KMP+dp)
题目链接:点击查看 题目大意:给出一个字符串,统计每个前缀在字符串中出现的次数之和 题目分析:可以直接先用后缀数组跑出来height,再用RMQ跑出来任意两个后缀的height,我们可以将题意转换为求 ...
- [BZOJ4556][TJOI2016HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1360 Solved: 545 ...
- 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过
题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...
- AcWing 蓝桥杯AB组辅导课 05、树状数组与线段树
文章目录 前言 一.树状数组 1.1.树状数组知识点 1.2.树状数组代码模板 模板题:AcWing 1264. 动态求连续区间和 例题 例题1.AcWing 1265. 数星星[中等,信息学奥赛一本 ...
- BZOJ.4553.[HEOI2016TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j)if(a[j ...
- 2019南昌网络赛 I. Yukino With Subinterval 树状数组套线段树
I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...
- 树状数组及线段树入门(SDNU1665-1668)
目录 前言 树状数组 先导 单点修改区间查询 区间修改区间查询 线段树 先导 单点修改区间查询--递归形式 单点修改区间查询--非递归形式 区间修改区间查询--递归形式 区间修改区间查询--非递归形式 ...
- HDU - 6194 string string string(后缀数组+RMQ+容斥)
题目链接:点击查看 题目大意:给出一个字符串和一个数字 k,问字符串中出现次数恰好等于 k 次的字串有多少个 题目分析:在跑完后缀数组后,我们可以用sa数组求解,具体做法是枚举起点,找长度为 k 的s ...
- hdu 5008 Boring String Problem(后缀数组+rmq)
题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...
最新文章
- 理解域信任关系,Active Directory系列之十六
- dedecms 会员网站UID注册名转MID
- SPOJ 287 Smart Network Administrator
- python输出乘法口诀-python以不同方式打印输出九九乘法表
- python分箱统计个数_【数据处理】python变量分箱常见手法:分类型、数值型、卡方、自定义...
- 商品进销差价_商品进销差价概述
- 手把手教你学dsp_新课免费看| 手把手教你学DSP,C2000从入门到精通
- Java模板方法中规定传的参数,java – 如何在Kotlin中实现模板方法设计模式?
- JS-以鼠标位置为中心的滑轮放大功能demo1
- python r语言 数据分析_PythonR语言-将Python和R整合进一个数据分析流程
- python爬虫之喜马拉雅非vip音频下载
- 如何在WPS里添加字体?
- Linux超详细指令及其解析
- apache ab压测与参数传递
- UVALive 3713 Astronauts(2SAT)
- 苹果电脑表格取消自动计算机,苹果电脑excel序列被隐藏怎么办
- 工业级嵌入式WiFi模块 无线网关智能家居 WiFi音视频传输模块 WiFi转有线网口模块方案
- 火车票能不能选座_电话订火车票可以自己选座位吗
- 开头决胜武器:软文开头的4种常用写法
- python入门部分基础知识(下)