传送门: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(线段树)相关推荐

  1. HDU - 4552 怪盗基德的挑战书(后缀数组+RMQ/KMP+dp)

    题目链接:点击查看 题目大意:给出一个字符串,统计每个前缀在字符串中出现的次数之和 题目分析:可以直接先用后缀数组跑出来height,再用RMQ跑出来任意两个后缀的height,我们可以将题意转换为求 ...

  2. [BZOJ4556][TJOI2016HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1360  Solved: 545 ...

  3. 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

    题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...

  4. AcWing 蓝桥杯AB组辅导课 05、树状数组与线段树

    文章目录 前言 一.树状数组 1.1.树状数组知识点 1.2.树状数组代码模板 模板题:AcWing 1264. 动态求连续区间和 例题 例题1.AcWing 1265. 数星星[中等,信息学奥赛一本 ...

  5. 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 ...

  6. 2019南昌网络赛  I. Yukino With Subinterval 树状数组套线段树

    I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...

  7. 树状数组及线段树入门(SDNU1665-1668)

    目录 前言 树状数组 先导 单点修改区间查询 区间修改区间查询 线段树 先导 单点修改区间查询--递归形式 单点修改区间查询--非递归形式 区间修改区间查询--递归形式 区间修改区间查询--非递归形式 ...

  8. HDU - 6194 string string string(后缀数组+RMQ+容斥)

    题目链接:点击查看 题目大意:给出一个字符串和一个数字 k,问字符串中出现次数恰好等于 k 次的字串有多少个 题目分析:在跑完后缀数组后,我们可以用sa数组求解,具体做法是枚举起点,找长度为 k 的s ...

  9. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

最新文章

  1. 理解域信任关系,Active Directory系列之十六
  2. dedecms 会员网站UID注册名转MID
  3. SPOJ 287 Smart Network Administrator
  4. python输出乘法口诀-python以不同方式打印输出九九乘法表
  5. python分箱统计个数_【数据处理】python变量分箱常见手法:分类型、数值型、卡方、自定义...
  6. 商品进销差价_商品进销差价概述
  7. 手把手教你学dsp_新课免费看| 手把手教你学DSP,C2000从入门到精通
  8. Java模板方法中规定传的参数,java – 如何在Kotlin中实现模板方法设计模式?
  9. JS-以鼠标位置为中心的滑轮放大功能demo1
  10. python r语言 数据分析_PythonR语言-将Python和R整合进一个数据分析流程
  11. python爬虫之喜马拉雅非vip音频下载
  12. 如何在WPS里添加字体?
  13. Linux超详细指令及其解析
  14. apache ab压测与参数传递
  15. UVALive 3713 Astronauts(2SAT)
  16. 苹果电脑表格取消自动计算机,苹果电脑excel序列被隐藏怎么办
  17. 工业级嵌入式WiFi模块 无线网关智能家居 WiFi音视频传输模块 WiFi转有线网口模块方案
  18. 火车票能不能选座_电话订火车票可以自己选座位吗
  19. 开头决胜武器:软文开头的4种常用写法
  20. python入门部分基础知识(下)

热门文章

  1. 955.WLB 不加班公司名单新增 5 家公司!2021 最新版!
  2. 一种级联前后端实现方案
  3. 《Java程序设计》课程代码题(九)
  4. Oracle数据库Bitand()函数用法(计算位移)
  5. 罗塞塔石碑(Rosetta Stone)安装指南
  6. Java程序员的技术进阶成长路线
  7. 如何重键盘输入“勾”“打勾””√“这个符号
  8. java基础-head first java
  9. 欧式空间与酉空间——概念区分
  10. 自己搭建项目中存在的一些问题