题目描述对于任何正整数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

题目

Step 1

这个是在openjudge上(7591)能A的代码(原题:输出l~r的所有反素数),因为那时n<=2e7啊。

当然也要讲一下原理。对于数的因子个数,不得不提唯一分解定理——n=a1^p1*a2^p2*…………其中a为该数的质因数,p为它的个数,比如49=7^2,其中a1=7,p1=2。于是因子个数为(p1+1)*(p2+1)*……(49有2+1=3个因子,1,7,49)。那么搜索的目的就很明显了,枚举质因子凑数字,凑出来的那一刻已经得到了它的因子个数!

给质数打个表,打多少呢?前十几个质数虽然都很小,但乘起来肥肠肥肠恐怖啊(不信你自己试一试),所以后面都不用了。

继续剪枝,举个栗子,2^3*3^2=72,2^2*3^3=108,它们的因子个数都为(2+1)*(3+1)=12,72明显小于108,也很明显如果把3的次方给2匀一个答案更优。同样的道理,2*3=6 < 2*5=10,如果质因数的组合不连续则一定存在更小的数比当前更优。

最后我们画一棵解答树,第一层是2^1、2^2、2^3……它们的分支都有3^1、3^2、3^3……之后还有5、7、11等等接着找(具体参考程序,id为第几个质因数,now是数的大小,tot是因子数)。

#include<cstdio>
#include<algorithm>
using namespace std;
int maxn,L,R,f,ans[20000010],p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
void dfs(int id,int now,int tot)
{ans[now]=tot;for(int i=1;now*p[id]<=R;++i) dfs(id+1,now*=p[id],tot*(i+1));
}
int main()
{scanf("%d%d",&L,&R);dfs(1,1,1);for(int i=1;i<L;++i) maxn=max(maxn,ans[i]);for(int i=L;i<=R;++i)if(ans[i]>maxn){maxn=ans[i];f?printf(","):f=1;printf("%d",i);}if(!f) puts("NO");return 0;
}

Step 2

如果能做到第一步,你就已经有一个不错的爆搜程序了,但对于2e9的范围来说还是弱了不少。仔细读题,发现这两道题还是有点区别的,我们不必求出这个范围内的所有反素数,只用找到那个最大的。既然这样,那我们就直奔答案寻找新的优化。更新条件有两个注意不要漏(估计只有像我这样头不好的人才会两次都写错……),之后参考Step 1的剪枝,我们尽量让小质数的次方数大,这也就意味着对于2^p1*3^p2*5^p3,满足p3<=p2<=p1。开个use数组记录一下p就好了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<cstring>
 7 #define ll long long
 8 #define inf 1<<29
 9 using namespace std;
10 int n,p[]={0,2,3,5,7,11,13,17,19,23,29,31},use[20];
11 ll maxt,ans;
12 void dfs(ll id,ll now,ll tot)
13 {
14     if(tot>maxt||(tot==maxt&&now<ans)) ans=now,maxt=tot;
15     use[id]=0;
16     while(now*p[id]<=n&&use[id]+1<=use[id-1]){
17         use[id]++;
18         now*=p[id];
19         dfs(id+1,now,tot*(use[id]+1));
20     }
21 }
22 int main()
23 {
24     scanf("%d",&n);
25     use[0]=1<<29;
26     dfs(1,1,1);
27     printf("%lld",ans);
28     return 0;
29 }

Step 3

用我之前的程序可以打出比较小的表(2e8以内),观察一下,发现反素数其实很少,而且越往后它们的间隔越大(147026880~183783600,△=3e7+)。这也就意味着我们不用一个一个数去枚举小于它的最大的反质数。于是,先记录2e9的答案为1396755360,再把它减一输入程序,不断重复该操作与小的表接起来。我们终于打出最后的表了。(不容易啊QAQ~~~~~)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ll long long
 4 using namespace std;
 5 int n,biao[]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360};
 6 int main()
 7 {
 8     scanf("%d",&n);
 9     for(int i=0;i<68;++i)
10         if(biao[i]>n){
11             printf("%d",biao[i-1]);
12             return 0;
13         }
14     printf("%d",biao[67]);
15     return 0;
16 }

转载于:https://www.cnblogs.com/12mango/p/7592925.html

luoguP1463:反素数ant(打表心得☆)相关推荐

  1. BZOJ 1053 [HAOI2007]反素数ant

    53: [HAOI2007]反素数ant Description 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4.如果某个正整数x满足:g(x)>g(i) 0< ...

  2. BZOJ(8) 1053: [HAOI2007]反素数ant

    1053: [HAOI2007]反素数ant Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4118  Solved: 2453 [Submit][ ...

  3. bzoj1053: [HAOI2007]反素数ant

    51nod有一道类似的题...我至今仍然不会写暴搜!!! #include<cstdio> #include<cstring> #include<iostream> ...

  4. [HAOI2007]反素数ant

    1053: [HAOI2007]反素数ant Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1907  Solved: 1069 [Submit][ ...

  5. bzoj 1053: [HAOI2007]反素数ant 51nod-1060:最复杂的数(反素数与因数个数计算)

    问题概述:把一个数的约数个数定义为该数的复杂程度,给出一个n,求1-n中复杂程度最高的那个数. 例如:12的约数为:1 2 3 4 6 12,共6个数,所以12的复杂程度是6.如果有多个数复杂度相等, ...

  6. 洛谷 P1463 [SDOI2005]反素数ant P1820 寻找AP数

    传送门1 传送门2 这个题又是一个双倍经验题. 对于这种题,我的思路从来都是: 1.暴力打表 2.找规律 3.试着写正解 首先打表,我当时打出了小于等于100000的所有符合条件的数,直接看也没看出来 ...

  7. 1053: [HAOI2007]反素数ant

    链接 思路 首先一个结论,对于一个数$n = p_1^{a_1}p_2^{a_2}...p_k^{a_k}$,它的因数的个数是$(a_1+1)(a_2+1)...(a_k+1)$,而且对于2,000, ...

  8. 2017.3.13 反素数ant 失败总结

    这个题放弃的非常彻底,因为我怀疑这需要我没学过的数论,不能白白耽误时间(其实是不想推) 第一眼感觉应该是欧拉函数的变种(去非整除数),但绝对不是线筛(太慢),感觉约数的个数这个条件很迷啊,给人最直观的 ...

  9. AcWing 198. [HAOI2007] 反素数 约数个数+dfs

    题 参考 约数个数:每个质因数的次数+1的乘积. 2e9<2x3x5x7x11x13x17x19x23; 2e9<pow(2,31); last其实是最多扫30次. #include< ...

最新文章

  1. 【多标签文本分类】SGM: Sequence Generation Model for Multi-Label Classification
  2. Linux脚本获取日期,Shell脚本获取格式化日期与时间
  3. 寺库等奢侈品电商补贴下的奢侈品市场,会是怎样的未来
  4. 【数据结构与算法】常用算法
  5. C++ 静态链表(用数组模拟动态链表)
  6. 15.concurrent-control并发控制
  7. 网络4/7层模型各层作用和协议对比
  8. (转载)项目实战工具类(一):PhoneUtil(手机信息相关)
  9. RedisTemplate value序列化导致的问题
  10. Git—代码管理、提交及冲突解决流程的思考
  11. 全部博文集锦第三期CHM文件,及十三个经典算法研究PDF文档
  12. Dart与系统进程交互
  13. 凉山州计算机等级考试时间,2020年四川凉山中考考试时间及科目安排(已公布)...
  14. org.jgroups.ChannelException: failed to start p...
  15. 入门必看,51单片机学习三步走
  16. 计算摄影学基础知识(1)
  17. Cortex-M0和Cortex-M0+简介
  18. 多智时代,人工智能发展历史的时间表
  19. go语言中如何使用select
  20. 软件设计师-3.数据结构与算法基础

热门文章

  1. android jxl.jar 使用,使用jxl.jar在Android中操作Excel表格——重中之重——对隐藏表的处理...
  2. python网络爬虫系列(一)——urllib库(urlopen、urlretrieve、urlencode、parse-qs、urlparse和urlsplit、request.Request类)
  3. LeetCode 1913. 两个数对之间的最大乘积差
  4. LeetCode 1824. 最少侧跳次数(DP)
  5. Java 包及访问权限
  6. [Kaggle] Spam/Ham Email Classification 垃圾邮件分类(RNN/GRU/LSTM)
  7. LeetCode 1674. 使数组互补的最少操作次数(差分思想)
  8. 剑指Offer - 面试题10- II. 青蛙跳台阶问题
  9. LeetCode 1346. 检查整数及其两倍数是否存在(哈希)
  10. LeetCode 38. 报数