反素数

题目描述

AcWing 198. 反素数 - AcWing

样例

1
2
输入:1000
输出:840

结论

1 如果一个数字m 它的质因子p1,p2,p3,p4,p5 它每个质因子的个数N1,N2,N3,N4,N5 那它的约数个数就为N1xN2xN3xN4xN5;
2 如果要是上面要使上述的m尽量的小,那它的每个质因子必然是紧挨着的,同时对应的质因子的N1>=N2>=N3>=N4>=N5
顺便说一下2∗3∗5∗7∗11∗13∗17∗19∗23∗29∗3>2*10^9 所以代码里面的线性筛没必要,枚举就可以了
如果每个质因子都一样大 那很明显 我尽量的把每个质因子的数量分为两分同时然后质因子也尽量多,那约数个数也就是
指数级最大,但是事与愿违,质因子分的多,同时拆分出的最大质因子也会变得很大所以要深搜,找出一个最佳的分配方案

时间复杂度

C++ 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include<bits/stdc++.h>

using namespace std;

int cnt=0;
int primes[100000];
bool st[1000000];
int qmi(int a,int b){
int ans=1;
while(b){
if(b&1) ans*=a;
a*=a;
b>>=1;
}return ans;

}
void init(int k)
{
for(int i=2; i<=k; i++)
{
if(!st[i]) primes[++cnt]=i;
for(int j=1; j<=cnt&&i*primes[j]<=k; j++)
{
st[i*primes[j]]=1;
if(i%primes[j]==0)break;
}
}
}
int mm=0;//最多约数的数量
int n;
int cc=999999;//递归找到当前状态下 出现最多约数的最小值
void dfs(int num,int k,int f,int ans)
{
if(ans==mm)cc=min(cc,num);//如果当前约数的数量等于目前最大的约数数量 那cc(也就是答案)要取两者最小
else if(ans>mm){//如果约数数量大于当前最大的 那就更新答案
mm=ans;
cc=num;
}

for(int i=1;i<=f;i++)//深搜下一个质因子
{
int h=qmi(primes[k+1],i);//快速幂也没必要 我是小丑
if((long long)h*num>n) break;//我的写法要加longlong 不然会爆
dfs(num*h,k+1,i,ans*(i+1));
}
}

signed main()
{
init(100010);

cin>>n;
for(int i=1; i<=30; i++)
{
if(1<<i>=n)break;
dfs(1<<i,1,i,i+1);//当前数值,多少个质数因子,最后一个数的次方,约数个数
}

cout<<cc<<endl;

}

所以呢就别不快乐。