1394 数字串

1394 数字串

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 钻石 Diamond

题解

查看运行结果

题目描述 Description

给你一个长度为n的数字串,数字串里会包含1-m这些数字。如果连续的一段数字子串包含了1-m这些数字,则称这个数字字串为NUM串。你的任务是求出长度最短的NUM串是什么,只需要输出这个长度即可。
1<=n,m<=200000

输入描述 Input Description

第一行给定n和m。 
第二行n个数,表示数字串,数字间用空格隔开。

输出描述 Output Description

如果存在NUM串则输出最短NUM串长度,否则输出“NO”。

样例输入 Sample Input

5 3
1 2 2 3 1

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

各个测试点1s

分类标签 Tags 点此展开

贪心

题意:

给定一个长度为n的序列,每个元素都是不大于m的正整数。找出最短的连续数段,满足每一个不大于m的正整数都在其中出现。n和m均不大于200,000。

最简单的想法是,暴力枚举左右端点形成序列,在序列中分别查找每个不大于m的正整数。时间复杂度O(n^3·m)。

可以想到的一个简单优化是,可以枚举左端点,然后不断向右扫描,用一个桶d[]来统计每个不大于m的正整数出现的次数。

则当d[]中的每个元素都大于0时,即每个不大于m的正整数都有出现时,结束当次扫描,修改最小值,选择下一个左端点。时间复杂度O(n^2·m)。

可以想到,每次只修改某单个d[i],即令d[i]增加1,却要把整个数组扫描一次来判断,是很浪费时间的。我们可以令cnt为d[]中值大于0的元素个数,且初始化为0。

每次令d[i]增加1后,若d[i]的变化是从0到1,则令cnt增加1。当cnt=m时就知道当前数段已经满足要求了,不必次次把d[]扫描一次。时间复杂度O(n^2+nm)。

但是本题要求一个线性的做法,每次选择好左端点然后从原地开始向右扫描,显然是二次方的。是否一定要从原地开始扫描呢?

令f[i]为当左端点为i时,最小的使得数段[i,j]满足要求的j。如n=5,m=3且序列为1,3,3,2,1,当左端点为1时向右扫描,直到扫描到第4个数,才能使得当前数段1,3,3,2满足要求。

而以2为左端点则要扫描到第5个数才可以。因此定义f[1]=4,f[2]=5,同理f[3]=5,而f[4]和f[5]为无穷大。则只需要在所有f[i]-i+1中找一个最小值即可。

应该注意到,f[i]关于i是单调的,当i增加时,f[i]不会减少。如果有i<j且f[j]<f[i],由于数段[i,f[j]]包含数段[j,f[j]],一定也是满足要求的,而数段[i,f[i]]比这还大,不可能是最小的。

当i=1时,可以进行朴素的扫描,即从原地开始。当i=2时,则只要从f[1]开始即可。更一般地,当左端点为i时,只要从f[i-1]开始即可,大大节省了时间。

但是,d[]和cnt要怎么维护呢?只需要在左端点i移动至i+1时,将d[i]减去1即可。如果d[i]的变化是从1到0,则令cnt减去1。右端点移动时,就按原来添加元素的方法去做即可。

AC代码:

#include<cstdio>
#include<iostream>
using namespace std;
#define N 201000
int n,m,num,a[N],vis[N];
int ans=0x3f3f3f3f;
int main(){
    freopen("sh.in","r",stdin);
    scanf("%d%d",&n,&m);
    int i,j=1;
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(i=0;num<m&&i<=n;){
        vis[a[++i]]++;
        if(vis[a[i]]==1) num++;
    }
    if(i>n){
        puts("NO");
        return 0;
    }
    for(ans=i;i<=n;i++){
        vis[a[i]]++;
        if(vis[a[i]]==1) num++;
        for(;(num>m)||(num==m&&vis[a[j]]>1);j++){
            vis[a[j]]--;
            if(vis[a[j]]==0) num--;
        }
        ans=min(ans,i-j+1);
    }
    printf("%d\n",ans);
    return 0;
}
时间: 2024-07-30 16:27:28

1394 数字串的相关文章

数字串(codevs 1394)

题目描述 Description 给你一个长度为n的数字串,数字串里会包含1-m这些数字.如果连续的一段数字子串包含了1-m这些数字,则称这个数字字串为NUM串.你的任务是求出长度最短的NUM串是什么,只需要输出这个长度即可.1<=n,m<=200000 输入描述 Input Description 第一行给定n和m. 第二行n个数,表示数字串,数字间用空格隔开. 输出描述 Output Description 如果存在NUM串则输出最短NUM串长度,否则输出“NO”. 样例输入 Sample

把数字串变成2012玛雅密码

问题: 玛雅密码是一串由0.1.2组成的密码,这串数字中如果包含2012,就可以解开末日的大门.给定一串由0.1.2组成的字符串,只有相邻的数字可以交换,求通过最少多少次变换可以得到玛雅密码,并给出这串密码. 思路: 经过很久很久的尝试,放弃了一次性拼凑2012的想法,改用预处理得到所有数字范围中符合玛雅密码的部分,再递归遍历给定的数字串,得到该串所有可能的变换,并比较每个变换的结果需要的步数. import sys def find_all_transfers(str): result={}

[华为]在字符串中找出连续最长的数字串

链接:https://www.nowcoder.com/questionTerminal/2c81f88ecd5a4cc395b5308a99afbbec来源:牛客网 样例输出 输出123058789,函数返回值9 输出54761,函数返回值5 接口说明 函数原型: unsignedint Continumax(char** pOutputstr,  char* intputstr) 输入参数:   char* intputstr  输入字符串: 输出参数:   char** pOutputst

在字符串中找出连续最长的数字串

输入描述: 输入一个字符串. 输出描述: 输出字符串中最长的数字字符串和它的长度. 输入例子: abcd12345ed125ss123058789,如果有重复的最大长度的数字串,则一起输出,如1456jk4789,输出14564789,4 输出例子: 123058789,9 思路:先把字符串中的数字串取出来,然后取出长度最大的数字字串并输出,刚开始我使用HashMap的key存储数字字串,value存字串长度,考虑到HashMap存储无序,故改为LInkedHashMap,然后根据Map的val

笔试算法题(37):二叉树的层序遍历 &amp; 最长递增的数字串

出题:要求层序遍历二叉树,从上到下的层次,每一层访问顺序为从左到右,并将节点一次编号,输出如下:如果只要求打印指定的level的节点,应该如何实现. a b  c d  e  f  g h  i  分析: 原始的层序遍历类似于BFS,打印当前访问的节点curNode的序列号,并将其直接子节点放入队列queue中,然后从queue中取出下一个节点,直 到队列为空:此方法仅能按照层序打印所有节点,并不能区分每一层节点的数量:如果需要区分当前层次的节点,和当前层次节点的子节点,可以使用两个队列 que

比较字符串和数字串(轉載)

比较字符串 和数字串 要比较字符 串(类型 C)和数字 文本(类型 N),可以 在逻辑表达 式中使用下 列运算符. <运算符>含 义 CO 仅包 含 CN 不仅 包含 CA 包 含任何 NA 不 包含任何 CS 包 含字符串 NS 不 包含字符串 CP 包含模 式 NP 不包 含模式 因为除类型 N和 C 外,系统不 能执行任何 其它类型转 换,所以, 在进行包含 这些运 算之 一的比较时 ,操作数应 该是类型 N 或 C. 运算符的功 能如下: CO (仅包含) 如果 <F1> 

在字符串中找出连续最长的数字串 在字符串中找出连续最长的数字串,并把这个串的长度返回

写一个函数,它的原形是int continumax(char *outputstr,char *intputstr)功能:在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串付给其中一个函数参数outputstr所指内存.例如:"abcd12345ed125ss123456789"的首地址传给intputstr后,函数将返回9, #include<iostream> using namespace std; int ContinueMax(char *

解决 PHPExcel 长数字串显示为科学计数

解决 PHPExcel 长数字串显示为科学计数 https://github.com/PHPOffice/PHPExcel/ 在excel中如果在一个默认的格中输入或复制超长数字字符串,它会显示为科学计算法,例如身份证号码,解决方法是把表格设置文本格式或在输入前加一个单引号. 使用PHPExcel来生成excel,也会遇到同样的问题,解决方法有三种: 1.设置单元格为文本 $objPHPExcel = new PHPExcel(); $objPHPExcel->setActiveSheetInd

parseInt在IE8转换返回不相等(parseInt(&quot;08&quot;)返回0等以0开头大于7的数字串)

描述 在IE8内核下parseInt("08")返回0,等以0开头大于7的数字串返回的值不相等 解决方法 parseInt当不指定radix时,当以0x开头时,s按照十六进制计算的:如果以0开头且第二位不为x,则s是按照八进制计算的,因为八进制不能有8,9所以报错返回0. 测试有效效果 parseInt("08",10)==8