zoukankan      html  css  js  c++  java
  • 反素数 Antiprime(信息学奥赛一本通 1625)(洛谷 1463)

    题目描述

    对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。

    如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。例如,整数1,2,4,6等都是反质数。

    现在给定一个数N,你能求出不超过N的最大的反质数么?

    输入格式

    一个数N(1<=N<=2,000,000,000)。

    输出格式

    不超过N的最大的反质数。

    输入输出样例

    输入 #1
    1000

    输出 #1

    840


     2019/8/21-更新(代码后面写不了了,只能写在前面...):

    上午刚做的题,下午老师就讲了,搞得我好像白写了题解o(一︿一+)o,所以就顺便把老师的课件附上来吧!

    (别忘了后面还有我自己写的...


    首先普及下关于“反素数”的两个性质:

    • 性质一:一个反素数的质因子必然是从2开始连续的质数.

    • 性质二:p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=....

    然后,我再说下我个人的理解

    • 因为题目给出了n的范围,所以我们可得出结论:n的质因子的种数不超过10,所以得到了一条递归边界;

    • 因为“反素数”的性质二,所以在两个数约数相等的情况下,更小的那个数就是“反素数”(可以用反证法证明:如果存在a的约数个数与b相等,且a>b。若认为a为“反素数”,那么不满足小于a的数的约数个数都小于a的约数个数,矛盾;)。所以我们要求的答案显然就是不大于n的  约数个数最大的  最小的数(哇这句话真的要好好理解,性质二肥肠关键!;

    • 那么应用到本题,在递归的过程中,如果遇到两个数约数个数相同,并且当前得到的数now小于之前得到的数ans,那就更新ans;如果当前求得的数now的约数个数num已经大于之前求到的最大的约数个数tot,那就更新tot,并且别忘了也要更新ans;

    • 如果在递归过程中,当前求得值已经大于n,那么就没必要再继续递归下去,直接返回,这就是第二条递归边界;

    • 在递归函数中设置一个循环,每进行一个循环,当前递归的质因子的个数就加一,并且此处还可以进行一点剪枝,在循环条件中加入“当前递归的质因子个数  不大于  比其小的质因子的 个数”这个条件;

    我在这里给出两种代码,思想大概就是我上面所述,只不过写法略有不同,大家可以选择自己更喜欢的一种啦~

    (顺便,看我码字不易,怎么说也给个“推荐”吧♪(^∀^●)ノ

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=1e6+5,inf=0x3f3f3f3f;
     4 int a[11]={0,2,3,5,7,11,13,17,19,23,29};//打表大法好(质因子种数不超过10)
     5 long long n,ans,tot;//tot为求到的最大的约数个数
     6 void f(long long x,long long now,long long shu,long long num)
     7 {
     8     //x为当前递归的质因子,now为当前求得的数,num为now的约数个数 
     9     if(x==11)return ;//递归边界1
    10     long long tmp=1,i;
    11     for(i=1;i<=shu;i++)//当前递归的质因子的个数不超过shu(想不到其他变量名惹...无奈词汇量太小) 
    12     {
    13         tmp*=a[x];//tmp暂时存储 
    14         if(now*tmp>n)return ;//递归边界2 
    15         if(num*(i+1)==tot&&now*tmp<ans)ans=now*tmp;//如果约数个数相同,并且当前得到的数now小于之前得到的数ans,那就更新ans;
    16         if(num*(i+1)>tot)//如果now的约数个数num大于之前求到的最大的约数个数tot,那就更新tot,并且更新ans;
    17         {
    18             tot=num*(i+1);
    19             ans=now*tmp;
    20         }
    21         f(x+1,now*tmp,i,num*(i+1));//往下递归 
    22     }
    23 }
    24 int main()
    25 {
    26     cin>>n;
    27     f(1,1,31,1);
    28     printf("%lld",ans);
    29     return 0;
    30 }

    我比较喜欢下面的代码↓↓↓

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=1e6+5,inf=1<<29;
     4 int a[11]={0,2,3,5,7,11,13,17,19,23,29},used[11];//used[i]是指表中第i个质因子的个数 
     5 long long n,ans,tot;
     6 void f(long long id,long long now,long long num)
     7 {
     8     //id指当前递归的是表中的第几个质数,now和num同上一种做法 
     9     if(num>tot)//同上一种做法 
    10     {
    11         ans=now;
    12         tot=num;
    13     }
    14     if(num==tot&&now<ans)ans=now;//同上一种做法 
    15     used[id]=0;//注意每次递归要更新 
    16     while(now*a[id]<=n&&used[id]+1<=used[id-1])//循环条件中也包含了递归边界2(然鹅这里没有用递归边界1 
    17     {
    18         now*=a[id];//now更新 
    19         used[id]++;//当前递归的质因子个数加一 
    20         f(id+1,now,num*(used[id]+1));//继续递归 
    21     }
    22 }
    23 int main()
    24 {
    25     cin>>n;
    26     used[0]=inf;//注意!要保证在对第一个质数进行递归的时候,循环可以进行下去,详见used[id]+1<=used[id-1] 
    27     f(1,1,1);
    28     printf("%lld",ans);
    29     return 0;
    30 }
  • 相关阅读:
    获取系统当前时间
    使用键盘控制窗体的移动
    打开和关闭输入法编辑器
    屏蔽系统的Ctrl+c/x/v操作
    按Esc键实现关闭窗体
    屏蔽Alt+F4关闭窗体
    将回车键转换为Tab键
    node.js入门学习(六)--express
    curl POST如何查看响应的Header(转)
    node.js入门学习(五)--Demo模块化改造
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/11387147.html
Copyright © 2011-2022 走看看