HDU6194(后缀数组 + rmq)

详细解析后缀数组(RMQ及LCP) 后缀数组的应用受到越来越多人的关注,本文详细介绍了后缀数组的基本原理以及LCP—最长公共前缀。最后给出了几道例题及解析。 立即下载

string string string

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1672    Accepted Submission(s): 482


Problem Description
Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly  k  times as an important string, and you need to find out how many substrings which are important strings.
 

Input
The first line contains an integer  T  ( T≤100 ) implying the number of test cases.
For each test case, there are two lines:
the first line contains an integer  k  ( k≥1 ) which is described above;
the second line contain a string  s  ( length(s)≤105 ).
It's guaranteed that  ∑length(s)≤2∗106 .
 

Output
For each test case, print the number of the important substrings in a line.
 

Sample Input
  
2 2 abcabc 3 abcabcabcabc
 

Sample Output
  
6 9
 

Source
 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6216 6215 6214 6213 6212 


解题思路:后缀数组,先处理出height数组,然后每次取连续的k个前缀,求他们的lcp,就是在这段区间出现k次的字符串的数量,但是这些字符串并不是每个字符串都出现k次,可能会出现大于k次的情况,我们减去这部分就行,在这段区间的上边界和下边界各处理一下就行,我们可以用st表或者线段树维护一下区间lcp最小值就行。注意:每次tp数组或者rrank数组要清0,不然会影响到height的计算。。


#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
typedef long long LL;
int kk;
int dp[maxn][30];
int Log[maxn];
char s[maxn];
int n, m;
int a[maxn];//原数组
int rrank[maxn];//第一关键字
int Rank[maxn];//第i个前缀排第几
int tp[maxn];//第二关键字,序号为第二关键字的排名,值为对应的第一关键字的位置
int c[maxn];//用于基数排序用的数组
int Sa[maxn];//后缀数组,排名为i的后缀是哪一个后缀
int Height[maxn];//排名为i的后缀与排名为i - 1的后缀的lcp
bool judge(int *x, int loc, int ww)
{
    if(x[Sa[loc]] == x[Sa[loc - 1]] && x[Sa[loc] + ww] == x[Sa[loc - 1] + ww]) return true;
    else return false;
}
void suffix()
{
    memset(tp, -1, sizeof(tp));//注意,一定要清0
    for(int i = 1; i <= n; i++) rrank[i] = a[i];
    for(int i = 1; i <= n; i++) tp[i] = i;
    for(int i = 0; i <= 128; i++) c[i] = 0;
    for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
    for(int i = 1; i <= 128; i++) c[i] += c[i - 1];
    for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
    m = 128;
    for(int w = 1, p = 0; w <= n; w += w, m = p)
    {
        p = 0;
        for(int i = n - w + 1; i <= n; i++) tp[++p] = i;

        for(int i = 1; i <= n; i++)
        {
            if(Sa[i] > w) tp[++p] = Sa[i] - w;
        }
        for(int i = 0; i <= m; i++) c[i] = 0;
        for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
        for(int i = 1; i <= m; i++) c[i] += c[i - 1];
        for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
        for(int i = 0; i <= n; i++) tp[i] = rrank[i];//重新计算rank的值
        rrank[Sa[1]] = 1;
        p = 1;
        for(int i = 2; i <= n; i++)
        {
            if(judge(tp, i, w)) rrank[Sa[i]] = p;
            else rrank[Sa[i]] = ++p;
        }
        if(p >= n) break;
    }
    for(int i = 1; i <= n; i++)
    {
        Rank[Sa[i]] = i;
    }
    int k = 0;
    Height[1] = 0;
    for(int i = 1; i <= n; i++)
    {
        if(k) k--;
        while(a[i + k] == a[Sa[Rank[i] - 1] + k])
        {
            k++;
        }
        Height[Rank[i]] = k;
    }
}
void initRmq()
{
    Log[0] = -1;
    for(int i = 1; i <= n; i++)
    {
        if((i&(i - 1)) == 0) Log[i] = Log[i - 1] + 1;
        else Log[i] = Log[i - 1];
        dp[i][0] = Height[i];
    }
    for(int j = 1; j <= 25; j++)
    {
        for(int i = 1; i <= n && (i + (1<<j) - 1) <= n; i++)
        {
            dp[i][j] = min(dp[i][j - 1], dp[i + (1<<(j - 1))][j - 1]);
        }
    }
}
int rmq(int l, int r)
{
    int d = r - l + 1;
    d = Log[d];
    return min(dp[l][d], dp[r - (1<<d) + 1][d]);
}
void init()
{
    n = strlen(s);
    memset(Height, 0, sizeof(Height));
    memset(a, -1, sizeof(a));//注意,一定要重置。在这里wa了无数次
    for(int i = 0; i < n; i++)
    {
        a[i + 1] = s[i];
    }
}
int main()
{
    //freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;
    //freopen("C:\\Users\\creator\\Desktop\\out.txt","w",stdout) ;
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &kk);
        scanf("%s", s);
        init();
        suffix();
        initRmq();
        LL ans = 0;
        if(kk == 1)
        {
            for(int i = 1; i <= n; i++)
            {
                LL value = (LL)(n - Sa[i] + 1);
                LL value1, value2;
                value1 = (LL)Height[i];
                if(i + 1 <= n) value2 = (LL)Height[i + 1];
                else value2 = 0;
                LL Max = max(value1, value2);
                if(value > Max) ans += value - Max;
            }
        }
        else
        {
            for(int i = 1; i + 1 <= n && i + (kk - 1) <= n; i++)
            {
                LL value = (LL)rmq(i + 1, i + (kk - 1));
                LL value1 = (LL)rmq(i, i + (kk - 1));
                LL value2;
                if(i + kk <= n) value2 = (LL)rmq(i + 1, i + kk);
                else value2 = 0;
                LL Max = max(value1, value2);
                if(value > Max) ans += value - Max;
            }
        }
        printf("%I64d\n", ans);
    }
    return 0;
}




基因组注释(Annotation) Annotation 阅读详情

相关推荐

从零开始掌握OBD-II:汽车诊断开发的核心技术与实战解析

本文深入解析OBD-II汽车诊断系统的核心技术,包括ECU通信协议、故障码解析及诊断工具开发实战。通过详细的协议分析和代码示例,帮助开发者快速掌握汽车诊断开发技能,实现从零到精通的进阶。特别适合从事汽车电子开发和OBD检测的技术人员参考学习。

weixin_42528780的博客 438

hdu 6194 - 后缀数组+线段树

题目链接:点击打开链接 题解思路:用后缀数组处理得到的hight数组后,对它再进行线段建树,维护的是区间内最小的一个值,那么我们每次取枚举一个长度为n的区间时,取它的最小值这表示从1-ans_min的字符串长度都是满足的,那么题目还要求正好n次重复,那么我们就再取两次一个的左边界加一的区间值,一个是右边界加一的区间值,取两值的max那么此区间可取范围就应该是(左右边界+1的max,ans_min

过路人丶的博客 1412

VsCode+JLink+GCC替代Keil开发GD32程序-个人总结

对个人使用vscode+Jlink开发GD32程序做了总结,供需要者参考。

MyCollege1999的博客 2763

HDU 6194 题解报告

HDU[6194] 后缀数组+ST表 题目大意,要求在指定的字符串中找到出现k次的不同子串有几种,不同子串之间可重叠, [题目](http://acm.hdu.edu.cn/showproblem.php?pid=6194)。 AC代码 #include <bits/stdc++.h> using namespace std; typedef long long ll; con...

NoNoEscape的博客 343

机器视觉:9点标定的原理与实现

标定就是将机器视觉处理得到的像素坐标转换成实际项目中使用到的毫米坐标。简单说即使看看实际单位距离内有几个像素,如下图所示,10mm的距离内有222个像素,那像素坐标和实际的毫米坐标就有个比例关系了。

m0_49968063的博客 1万+

解决Keil uVision许可证管理中Unknown Product错误

嵌入式开发中,IDE工具的许可证管理是确保开发环境正常运行的关键环节。Keil uVision作为ARM架构的主流开发工具,其许可证系统采用加密验证机制,通过产品版本识别实现授权控制。当出现Unknown Product错误时,通常源于版本兼容性问题或区域发行版差异,这直接影响开发工具链的可用性。特别是在维护历史项目或使用中国特供版时,开发者常会遇到此类问题。通过分析许可证类型、调整安装配置或建立虚拟化开发环境等工程实践方案,可以有效解决这类授权验证故障,保障嵌入式项目的持续集成与交付效率。

weixin_33743248的博客 363

ural1297 后缀数组+RMQ

RMQ即求区间(i,j)的最值。通过O(nlogn)处理,O(1)给出答案。 RMQ主要是动态规划来做。dp[i][j]表示从i开始的长为2^j的区间最值。 那么可以得到dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); dp[i][j],这个区间可以分为2段(可以重叠),那最值就是这两段的最值。 查询时要找到那个j,那j=(int)...

weixin_30807677的博客 165

嵌入式C开发必备:用Cursor规则搞定代码风格检查(附Pikachu项目实战)

本文以Pikachu开源项目为例,详细介绍了如何利用Cursor的AI代理规则系统,为嵌入式C开发项目配置一套完整的代码风格检查与规范执行方案。通过实战演示,指导开发者创建项目级规则,实现命名、格式、硬件抽象层及驱动开发的自动化规范,从而提升代码一致性、可维护性和团队协作效率。

weixin_29181861的博客 598

【后缀数组+RMQ】 SPOJ 687

后缀数组

Starry_starry_night的博客 439

FPGA编译加速实战:6大可落地的Vivado优化策略

FPGA编译本质上是NP-hard约束满足问题求解,而非传统软件编译;Vivado作为时序驱动的硬件实现工具链,其耗时瓶颈集中在Implementation阶段的布局布线(PnR)与逻辑优化。理解这一原理,才能跳出‘加线程’‘升版本’等表面优化,转向精准时序约束、增量编译、物理锚点控制、IP配置精简等工程级干预。这些技术手段直接作用于Vivado的Tcl执行流与底层求解空间,显著压缩搜索范围、减少无效迭代——尤其适用于Zynq/UltraScale等中大型项目(LUT > 80K、多时钟域、DDR/PCIe

weixin_34226182的博客 413

C#上位机开发实战全流程:从需求到落地,避坑指南+完整代码

作为一名做了5年工业自动化上位机开发的程序员,我踩过的坑比写过的代码还多——从最初串口通信粘包导致数据错乱,到可视化图表卡顿卡死,再到现场异常崩溃无日志可查,每一次踩坑都是一次血泪教训。今天这篇文章,我会把C#上位机开发的全流程拆解开,从需求分析到通信模块、数据可视化,再到异常处理,每个环节都结合工业实际场景,分享真实项目中能用的方案、完整代码和避坑技巧。不管你是刚入门的新手,还是想优化现有项目的老司机,相信都能有所收获。很多新手做上位机开发,一上来就闷头写代码,最后发现做出来的东西不符合现场需求——比如客

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 995

hdu 3693 Math teacher's homework(数位dp)

题意:给出n个数,每个数字代表0到这个数字的范围,每个里面要选一个,求异或和为K的情况总数。 做法:挺难想的一个dp,我们把这些数换成2进制组成一个表格,首先可以明确一点,只要有一位可以随便放的二进制数的位(因为前面有的位已经使得比原数小了)不随便放,那么其他数这个位的0或1随便放,都可以达到想要的答案。而每一个位只需要一个这样的位就可以达到效果了,所以我们就规定第一个能随便放的地方不随便放,这

glq007的acm的奋斗 1693

【PX4学习笔记】3. PX4 固件烧写(1 探索过程)

飞控型号:cube orange【PX4官方用户指南中关于cube orange的描述】 飞控载板型号:Mini Carrier Board【迷你载板说明文档】 固件安装参考:The Cube User Manual V1.0

【人工智障 | 计算鸡视觉 | 机器孩】 7676

hdu 6194 后缀数组+RMQ

string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 616    Accepted Submission(s): 171 Problem Description Uncle M

扬帆起航 560

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

HDU 6194 string string string(后缀数组+RMQ)

string string string Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 608Accepted Submission(s): 167 Problem Description ...

weixin_30387339的博客 84

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

hdu 6194 后缀数组+RMQ+lcp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194 题意 给你一个字符串,要你求出这个字符串中正好出现k次的子串的个数有多少个。 花了很长一段时间,因为发现板子好像错了,找了好久的bug,就当现在又更新了一遍板子... 做法: 我们要找连续出现k次的,肯定是从sa数组下手,因为sa[i]...

人生如戏 298

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

HDU 6194 string string string 后缀数组 + RMQ(线段树)

传送门:HDU6194 题意:问给定字符串中有多少种出现k次的子串。 思路:首先想到后缀数组经典问题,求出现不少于k次的子串的最大长度,类似的这题肯定就是在height数组上搞事情啦。 将height数组每相邻k - 1个一组,这k - 1个height[i]中最小的那个设为tmp,就表示这排名相邻的k个后缀的最长公共前缀(设为s)长度为tmp,可以得出s出现了至少k次,那么长度为tmp -

WA是一笔财富 693

hdu6194 string string string(后缀数组+RMQ)

题目 给你一个串(串长&lt;=1e5),一个k(k&gt;=1) 问串中恰好出现k次的子串有多少个 思路来源 https://www.cnblogs.com/weeping/p/7503972.html 题解 先建后缀数组和high数组, high[i]代表排名为i和排名为i-1的最长公共前缀 注意到出现k次的子串长度的上界为长度为k-1的区间的最小值 而出现k+1次的子...

小衣同学的博客 311

hdu6194 string string string 后缀数组 + RMQ

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6194题意:给定一个字符串,求恰好出现k次的子串有多少个思路:后缀数组处理出height数组,然后按顺序每次取一个长度为k的区间,这个区间的公共前缀设为L,即这个区间内的height数组的最小值,可以RMQ实现O(1)查询,那么意味着有L个子串出现了恰好k次,但是有可能这L个子串中有一些出现次数是大于k的,要

弱智就要多努力 329

HDU-6194 后缀数组+lcp+rmq

题目string string string题意给一个字符串,问该字符串中出现次数正好为 k 次的不同子串个数。题解后缀数组+lcp+rmq。先用后缀数组求出高度数组 lcp。然后遍历 lcp,加上出现 k 次的子串个数: ans+=max(lcp[i]...lcp[i+k−2])ans += max(lcp[i]...lcp[i + k -2]) 还要减去子串出现大于k次的: ans−=m

Li_Yufeng的博客 404

hdu 6194 string string string 后缀数组+rmq+容斥

string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1531    Accepted Submission(s): 440 Problem Description Uncle

overload1997 384

string string string HDU - 6194 (后缀数组+lcp+RMQ)

题目链接:https://cn.vjudge.net/problem/HDU-6194 题意:给你一个字符串,让你求出恰好出现k次的子串的个数 思路,后缀数组求出sa数组,lcp求出lcp数组,RMQ来查询(线段树也可以) 查找的是 按照k的大小为一个区间长度来查询[i, i+k-1],然后还需要减去 至少出现k+1次的子串[i-1, i+k-1] 和[i,i+k],还得加上 [i-1...

zx93的博客 194

HDU 6194

  题意:告诉你一个字符串和k , 求这个字符串中有多少不同的子串恰好出现了k 次。 链接:HDU 6194 思路:后缀数组搞起! 首先处理出来Height数组,然后初始化ST表,那么我们从头开始RMQ查询长度为k的区间,那么区间最小值那个前缀至少出现了k次,然后我们将区间左右扩展,目的就是为了去除超过k次的,然后减掉多出来的就可以。   #include&lt;bits/stdc+...

qq_33688997的博客 437

HDU 6194 string string string 后缀数组+rmq

题目链接题意问一个字符串有多少个子串出现恰好 kk 次思路求出 heightheight 数组后,对于相邻的 kk 个后缀,它们包含恰好出现 kk 次的子串当且仅当 k−1k-1 个 heightheight 值中的最小值 >\gt max{max\{其中第一个与前一个的公共前缀,其中最后一个与后一个的公共前缀}\},差值即为这一段的个数。遍历一遍统计即可,最小值用 rmqrmq。注意 k=1k=1

kkkkahlua的博客 332

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

题目链接:点击查看 题目大意:给出一个字符串和一个数字 k,问字符串中出现次数恰好等于 k 次的字串有多少个 题目分析:在跑完后缀数组后,我们可以用sa数组求解,具体做法是枚举起点,找长度为 k 的sa数组的最长前缀就是出现至少k次的答案了,但是不能保证所有子串恰好出现了k次,所以我们在累加答案后再减去出现至少k+1次的答案,最后因为容斥原理还需要加上一部分,因为出现k+1次,多出来的一次可以...

Falcon的博客 475

HDU 6194 string string string( 后缀数组+RMQ)

string string string Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1462Accepted Submission(s): 420 Problem Description Uncle Mao is a w...

weixin_30563917的博客 116
上一篇: hihoCoder1403(后缀数组 + 二分)
下一篇: POJ1469(匈牙利算法求二分图最大匹配)
creatorx
博客等级 码龄10年 127粉丝 145原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值