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;
}




【电机控制入门】——电机控制书籍推荐 电机控制入门书籍推荐及分享 阅读须知: 1.电机控制的入门是涉及到机械、电子与控制等复杂交叉学习,它需要持续投入时间才可以看到学习的效果,如同“一万小时定律”。俗话说,九层之台,起于垒土,因此电机控制入门没有所谓的速成培训班。相反,还需要夯实好一定的基础。为此,博主建议从基础理论抓起,故推荐相关的书籍并分享给大家。 2.学习电机贵在动手实践,无论是借助于MATLAB/Simulink仿真平台来验证理论分析,或是使用板子对所设计的控制系统进行物理实现,博主极力推荐在一定基础(看完部分以下推荐的书籍),一边动手 阅读详情

相关推荐

Wireshark 4.6 TCP 流图解析:3种拥塞控制算法可视化对比

本文深入解析Wireshark 4.6的TCP流图功能,通过可视化对比Reno、Cubic和BBR三种主流拥塞控制算法的性能特征。文章提供详细的实验环境搭建方法、流图分析工具使用技巧,以及算法调优建议,帮助网络工程师优化TCP性能。

weixin_29291573的博客 446

hdu 6194 - 后缀数组+线段树

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

过路人丶的博客 1412

基于多智能体深度强化学习的空地协同通信系统轨迹设计与访问控制

所属子方向: UAV assisted communication 名词注释 coordinated:协调、协同 base stations 基站,公用移动通信基站,是移动设备接入互联网的接口设备,是指在一定的无线电覆盖区中,通过移动通信交换中心,与移动电话终端之间进行信息传递的无线电收发信电台。 UAV-BS:无人机基站 cooperative-competitive game:合作竞争博弈 throughput :吞吐量,每秒比特数 bps,bits per second Determinis

skysys的研究小屋 4969

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

【scratch音乐课】天空之城:音符与节拍、消息与链表

scratch是一个非常小巧的青少年编程工具,自带程序编写语句,积木式语句非常直观、易用,可创作数学、科学、音乐、绘画等方面作品。本文用scratch“演奏”一首大家非常熟悉的《天空之城》,并向大家介绍一些基本乐理知识,以及scratch中消息、链表的使用。

★·°立芯;︶︵︶ 1万+

5、Raspberry Pi CPU架构与多线程编程详解

本文详细介绍了Raspberry Pi的CPU架构(包括ARMv6Z、ARMv7-A和ARMv8-A),通过/proc/cpuinfo解析硬件信息,并深入探讨了多线程编程的核心技术。内容涵盖pthread库的使用,如线程创建、属性设置、等待与分离、线程同步机制(互斥锁),以及实际应用场景如多媒体处理和网络服务。同时强调了线程安全、死锁预防和资源管理等关键注意事项,帮助开发者在Raspberry Pi上构建高效稳定的多线程应用。

sre5engineer的博客 95

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

OpenStack [ compute_id ] 设计上的小缺陷

而 nova 代码中硬编码(或默认配置)将 compute_id 放在 site-packages 目录,属于 设计上的小缺陷—— 把 “库安装目录” 和 “运行时数据目录” 混在一起了,才导致需要临时调整这个目录的权限。# 配置项说明:node_identity_file 是 nova 用于指定节点标识文件路径的官方配置项,优先级高于代码中的默认路径。自定义 compute_id 路径,指向 /var/lib/nova/ 目录下的 compute_id 文件;

求知若渴,虚心若愚。 491

【后缀数组+RMQ】 SPOJ 687

后缀数组

Starry_starry_night的博客 439

一键开关机电路

一键开关机电路

让你爱上电路设计 4180

【深度学习|语义分割之UNet】如何使用ResNet50 作为 U-Net 网络的骨干网络(backbone)并使用预训练的 ResNet50 模型。附代码及解读。

【深度学习|语义分割之UNet】如何使用ResNet50 作为 U-Net 网络的骨干网络(backbone)并使用预训练的 ResNet50 模型。附代码及解读。

985小水博的摸鱼日常 3090

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

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

glq007的acm的奋斗 1693

【27】软考软件设计师——数据流图(DFD)补全题满分精讲|下午15分大题深度拆解

本文是《软件设计师·50讲通关|从零基础到工程师职称》专栏第27篇,深度精讲**下午案例题第1道必考大题:数据流图(DFD)补全**,该题单题分值高达**12 ~ 15分**,是整张试卷最稳的保底得分大题。我结合多年备考复盘与真题阅卷规则,超详细拆解DFD四大核心元素标准定义、机考绘图规范、三层分层逻辑、**父图子图平衡刚性扣分规则**,升级强化版「DFD满分补全三步法」;复刻历年高频真题完整流程,拆解缺失数据流定位、实体/存储辨析、平衡改错、文字需求对照全流程,配套**阅卷满分答题话术、机考避坑细则

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 590

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

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

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

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

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

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

hdu 6194 后缀数组+RMQ+lcp

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

人生如戏 298

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

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、付费专栏及课程。

余额充值