[bzoj]1053反质数<暴搜>

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1053

感想:这道题拿到以后还是想去知道一个数的约数个数要怎么求,去网上搜了公式,但是还是没有思路,最后看了好几个大佬的博客我才勉强知道这道题怎么做

  其实我看见这数据范围我就下意识觉得搜索会爆,但是实际上这道题不会爆的

方法:首先约数的个数求法

  已知数n=2^a + 3^b + 5^c + 7^d +……+ 第i个素数^x

  约数个数=(a+1)*(b+1)*(c+1)*(d+1)*……*(x+1)

  在知道这个公式后就可以用暴搜了,但是还是要知道就是数据范围内,素数最多就12个,所以预处理前几个素数

  还是看代码吧,我在代码中加了一些注释

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #define maxn 2000000005
 8 using namespace std;
 9 
10 const int prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
11 
12 int n,m,ans,ans_tot;
13 
14 //设一个数n=2^a + 3^b + 5^c + 7^d +……+ prime[dep]^x;
15 //则这个数的约数个数为(a+1)*(b+1)*(c+1)*(d+1)*……*(x+1)
16 //这是约数个数计算公式 
17 
18 void fuck(int dep,long long now_val,int tot,int num)
19 {
20 //dep=当前是prime中的素数的下标
21 //now_val是当前的值
22 //tot指当前的约数的个数
23 //num是上一个素数(prime[dep-1])的幂 
24     if(dep==11) 
25     {
26         if(now_val>ans&&tot>ans_tot){
27             ans=now_val;ans_tot=tot;
28         }//当发现比ans还大的数且这个数的约数个数比ans多
29         //即找到一个更优的解
30         if(now_val<=ans&&tot>=ans_tot)
31         {
32             ans=now_val;ans_tot=tot;
33         } //当发现一个比ans小但是约数比ans多的数
34         //说明ans不是一个反素数,也可以更新答案
35         return; 
36         
37     }
38     int t=1;
39     for(int i=0;i<=num;i++)
40     {
41         fuck(dep+1,now_val*t,tot*(i+1),i);
42         //搜下一个素数,又i从0次方开始的,所以now_val*s,s=1;
43         //约数的公式可以知道这是tot*(i+1) 
44         //到这个时候,prime[dep]已经i次方了,所以幂是i 
45         //其实可以想到最优解是小素数的幂越大越优,所以加num限定 
46         t*=prime[dep];//t表示当前素数prime[dep]的i次方 
47         if(now_val*t>n)break;//当乘不下去了就跳出 
48         
49     }
50     
51 }
52 
53 int main()
54 {
55     scanf("%d",&n);
56     fuck(1,1,1,30);
57     printf("%d",ans);
58 }

以上皆为看了大佬博客后的理解,如有不对,请大佬们指出

原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7182142.html