1087 有多少不同的值 (20 分)

    xiaoxiao2023-11-19  144

    1087 有多少不同的值 (20 分)

    题意描述:

    当自然数 n 依次取 1、2、3、……、N 时,算式 ⌊n/2⌋+⌊n/3⌋+⌊n/5⌋ 有多少个不同的值?(注:⌊x⌋ 为取整函数,表示不超过 x 的最大自然数,即 x 的整数部分。)

    输入格式: 输入给出一个正整数 N(2≤N≤10^​4​​ )。

    输出格式: 在一行中输出题面中算式取到的不同值的个数。

    输入样例:

    2017

    输出样例:

    1480

    解题思路: Alice: 这道题看起来有点熟悉呀。 Bob: 题目做的多了,翻来覆去也就这么多类型了。 Alice: 这题是要去重啊,直接顺着题目的逻辑来就行了,遍历,求值,用set去重,最后输出集合的大小。 Bob: 嘿,咱俩想的一模一样啊。 Alice: 现在觉得那句“人生苦短,我用Python”还是有些道理的。Python中很多内置对象类型真的是使用频率很高的啊。比如说set( ) Bob: 是啊,C++的话还要再使用<set>模板库。不过这道题目不用set也能做,就是麻烦一点。 Alice: 不用set ⊙(・◇・)?用数组重复打标记,最后在把有标记的值找出来? Bob: 对呀对呀,[]~ ( ̄▽ ̄)~*


    代码:

    一份Python实现,使用了set( ) def main(): N = int(input()) # 接收输入的整数N values = set() # values是一个集合,用来存储所有的不同的值 for x in range(1, N + 1): # 当自然数x依次取1 2 3 ... N时 values.add(int(x / 2) + int(x / 3) + int(x / 5)) # 将算式不同的值添加到values当中,由于集合中元素的唯一性,相同的值将只被记录一次 print(len(values)) # 由于集合中的每个元素都是唯一的,所以集合大小就是不同取值的个数 if __name__ == '__main__': main() 一份C++语言实现,只使用了数组。 #include <stdio.h> #define NN 10334 // 为什么是10334 ? 因为 10000 / 2 + 10000 / 3 + 10000 / 5 == 10333.3333... int flags[NN]; // 我们使用flags来存储所有不同算式的值,如某个算式的值是0,就有flags[0] == 1 int main() { int N, value; scanf("%d", &N); // 读入整数N for(int i=1;i<=N; ++i){ // 对从1 到 N 的每个整数 i value = int(i / 2) + int(i / 3) + int(i / 5); // 计算这个整数对应的算式的值 //printf("%d %d %d\n", int(i/2), int(i/3), int(i/5)); flags[value] = 1; // 记录这个值,如果有些值出现了多次,也只是重复执行,最终的记录结果和只出现一次是一样的。 } int count = 0; // 计算共有多少个不同的值出现 for(int i=0; i < NN; ++i){ if(flags[i] == 1){ // flags[i] == 1说明i作为某个算式的值至少出现了一次 count ++; // i 是一个不同于其他值(..i-2,i-1, i+1,i+2...)的值 } } printf("%d\n", count); // 输出共有多少个不同的值 return 0; } 另一份C++语言实现,使用了set( ) #include <stdio.h> #include <set> // 使用C++模板set需要先包含此文件 using namespace std; // 同样需要声明命名空间 int main(){ int N; set<int> values; // 声明一个整型的集合容器 scanf("%d", &N); // 读入正整数 N for(int i=1; i<=N; ++i){ values.insert(int(i / 2) + int(i / 3) + int(i / 5)); // 向集合中添加 每个 n 对应的算式的值 } printf("%d\n", values.size()); // 由于集合的特性,集合中没有重复的元素存在,所以集合的大小就是不同值的个数 return 0; }

    易错点:

    使用数组实现的时候,10000 / 2 + 10000 / 3 + 10000 / 5 == 10334 。对于边界值要多多关照,谨防数组越界访问带来的段错误。

    总结:

    这道题目中,我们遇到了一个比较常见的问题,去重。给定一个数组或者列表,其中有些元素重复出现,如何得到这些元素的集合呢 ? 如 [1, 1, 2, 5,,5 ] => {1, 2, 5}

    第一种方法: 使用编程语言的内置对象set,比如说Python。或者是语言的模板库,比如说C++语言的<set>。向set( ) 中直接传入一个待去重的列表就可以得到一个去重后的集合。或者先声明一个set对象,然后一个一个的往里面添加元素,重复的元素将不会被再次添加。第二种方法,使用数组或列表对不同的元素做出标记,然后找出所有不同的元素。如待去重数组是[1, 1, 2, 5, 5], 其中最大元素是5,,我们先声明一个 大小为6的数组并初始化为 [0, 0, 0, 0, 0, 0], 然后将对应的位置打上标记 [0, 1, 1, 0, 0, 1], 最后得到去重后的元素数组[1, 2, 5]。这种方法虽然看起来很酷,但是有一些缺点:1)复杂,2)需要以待去重元素中的最大值为大小的数组,占用内存较多。3 ) 鲁棒性差,无法处理多种数据类型的去重。如["U", 2, 2, 5, 5]。
    最新回复(0)