• 蓝桥杯 试题 历届试题 幸运数 筛法


    问题描述

    幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成

    首先从1开始写出自然数1,2,3,4,5,6,....

    1 就是第一个幸运数。

    我们从2这个数开始。把所有序号能被2整除的项删除,变为:

    1 _ 3 _ 5 _ 7 _ 9 ....

    把它们缩紧,重新记序,为:

    1 3 5 7 9 .... 。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被3整除!! 删除的应该是5,11, 17, ...

    此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,...)

    最后剩下的序列类似:

    1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, ...

    输入格式
    输入两个正整数m n, 用空格分开 (m < n < 1000*1000)
    输出格式
    程序输出 位于m和n之间的幸运数的个数(不包含m和n)。
    样例输入1
    1 20
    样例输出1
    5
    样例输入2
    30 69
    样例输出2
    8
    解题思路:此题与素数筛法不同的地方在于筛选的是位置下标而不是数值,解题的关键是如何保存每次筛后的数组。
    思路1:记录需要向前压缩的步数,每次筛去数字后向前的压缩的步数+1。
    #include<cstdio>
    /*记录每次压缩后的步长*/
    
    const int Max_N = 1000000;
    
    int m,n;//输入
    
    int nums[Max_N]; //保存数字
    
    void solve()
    {
        //初始化 
        for( int i=0; i<n; i++ )
        {
            nums[i] = i+1;    
        }    
        
        int step, key = 2, pos = 1, res = 0;
        //step:压缩步长 key:当前幸运数 pos:幸运数在nums的下标 res:(m,n)幸运数的和
        while( key<n )
        {
            step = 0;
            for( int i=0; i<n; i++ )
            {
                if( nums[i]!=0 )
                {
                    if( (i+1)%key==0 ) //需要被筛去 
                    { 
                        nums[i] = 0;  //筛去 
                        step++;     //压缩步长+1 
                    }    
                    else
                    {
                        nums[i-step] = nums[i];  //向前压缩
                        if( step>0 )
                        {
                            nums[i] = 0; //如果num[i]向前压缩至i-step 则num[i]清零    
                        } 
                    }
                }    
                else    break; //nums[]已经全被压缩 
            }    
            
            key = nums[pos++]; //更新幸运数 
            if( key==0 )    break; //已经没有幸运数了(nums[]后面的数均为0)
            /*特别注意:要在key更新后立即判断 否则之后可能涉及余0操作 结果出错*/
            
            if( m<key&&key<n )    res++; //更新res
        } 
        
        printf("%d
    ",res);
    } 
    
    int main()
    {
        scanf("%d%d",&m,&n);
        
        solve();
        
        return 0;
    }
    View Code

    思路2:用一个二维数组交替保存筛去后的数字。

    #include<cstdio>
    
    const int Max_N = 1000000;
    
    int m,n; //输入
     
    int nums[Max_N][2]; //用两个数组交替保存筛过之后的数 
    
    void solve()
    {
        //初始化 
        for( int i=0; i<n; i++ ){
            nums[i][0] = i+1;
        }
        
        int flag = 0,pos = 1,key = 2, length = n;
        //flag:用于交替操作     length:循环长度(这里没有把筛去的数字变为0) 
        while( key<n )
        {
            //从num[][from]保存至num[][to] 
            int from = flag%2, to = (flag+1)%2;
            int index = 0;
            for( int i=0; i<length; i++ )
            {    
                if( (i+1)%key!=0 ){ //把不被筛去的数字保存至另一个数组里 from-->to 
                    nums[index++][to] = nums[i][from];
                }
            }
            length = index;// 更新循环长度 
            
            key = nums[pos++][to];
            if( key==0 )    break;
            
            flag++; // 更新flag 交替保存 
        }
        
        //最后记录res  在循环内直接记录res会因为继续交替两个数组而出错 
        int res = 0 , to = (flag+1)%2;
        for( int i=0; i<length; i++ )
        {
            if( m<nums[i][to]&&nums[i][to]<n )    res++;
        }
        
        printf("%d
    ",res);
    }
    
    int main()
    {
        scanf("%d%d",&m,&n);
        
        solve();
        
        return 0;
    }
    View Code
  • 相关阅读:
    Medium | LeetCode 11. 盛最多水的容器 | 双指针
    Hard | LeetCode 41. 缺失的第一个正数 | 原地Hash
    Navicat Premium 15 使用注册机破解,附带Navicat Premium 15安装包、注册机下载
    vue $forceUpdate() 强制重新渲染
    js 原生录制屏幕
    mysql 8.0.17 解压版安装教程
    vue 移动端适配 amfe-flexibl
    mysql重置密码
    2059-Authentication plugin'caching_sha2_password'cannot be loaded
    用js实现时间减去前1小时、7天、1月、1年
  • 原文地址:https://www.cnblogs.com/w-like-code/p/13412655.html
Copyright © 2020-2023  润新知