一、约数
1.定义
约数,又称因数。整数a除以整数b(b≠0) 除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a。a称为b的倍数,b称为a的约数。
2.唯一分解定理
任意大于1的自然数都可以分解为有限个素数之积
即
A
a
×
B
b
×
C
c
.
.
.
×
Z
z
A^a \times B^b \times C^c... \times Z^z
Aa×Bb×Cc...×Zz的形式
3.求约数个数及约数和
求约数个数
对于任意一个约数来说,都是由不同指数下的质因数所组合而成
只要指数搭配不同就意味着约数不同
对于每个质因数来说,有0到
c
i
c_i
ci种选法,且不同质因数之间选择无影响,那么所有约数的个数也就是组合的结果。
求约数之和
将上式展开可得质因数的不同组合,即约数之和。
可以推广至求约数平方之和,将每一项先进行平方处理即可。
二、反素数
1.定义理解
定义:对于任何正整数n,其约数个数记作 f( n ),
如果某个正整数n满足:对任意的正整数
i
(
0
<
i
<
n
)
i (0<i<n)
i(0<i<n),都有
f
(
i
)
<
f
(
n
)
f( i ) < f( n )
f(i)<f(n),那么
n
n
n称为反素数。
2.性质
若n为反素数
质因数为从2开始的连续若干个质数
有
每个正整数都有它的约数,在约数个数相同的一类数中,那个值最小的数就是反素数。
反证法:
若最小数不为反素数,那么此时的反素数之前存在一个数的约数个数等于反素数的约数个数,不满足定义。
既然约数个数相同就意味着质因数的指数+1的积相同,此时又要保证该数的值为最小,那么大的指数必定要位于前端,即指数整体按递减排列。
3.寻找约数个数为n的反素数
例题:Number With The Given Amount Of Divisors
数据保证了这个反素数的大小不会超过 1 0 18 10^{18} 1018,那么我们就可以确认至少需要多少个质因数。
质因数个数不会超过16个
前
16
16
16个质因数之积大于
1
0
18
10^{18}
1018
所以我们搜索的时候只要在前 16 16 16个质因数里面进行搜索就行了。
4.代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int prim[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
ull minx;
int n;
void dfs(int u,ull a,int b){//当前质因数位置,当前值,约数个数
if(b>n||u>=16)return;
if(b==n&&a<minx){//不断更新minx的值
minx=a;
return;
}
for(int i=1;i<=63;i++){//???
if(a*prim[u]>minx)break;
a*=prim[u];
dfs(u+1,a,b*(i+1));
}
}
int main(){
cin>>n;
minx=~0ull;//一开始我直接写为INT_MAX,忘记了ull,还是小了,过不了第八组数据,要注意一下
dfs(0,1,1);
cout<<minx;
}
5.在n范围内最大的反素数
则必有该点约数个数最多。
证明:令该点为
a
a
a,作为反素数,其左侧约数个数一定小于它,不考虑;
若其右侧存在一个数,且这个数的约数个数大于
f
(
a
)
f(a)
f(a),那么
a
a
a并不是
n
n
n范围内最大的反素数,仍然有一个数不仅值更大,约数个数也更多。
在约数个数相同的一类数中,其值为最小。
证明:若不为最小,则小于该值的数中存在数不满足定义,那么该值也就不是反素数。
我们目标就是找出满足上述两个条件的那个点。
除此以外,根据题目的数据要求,我们还可以得到另外两个性质:
1.此时质因数不会超过10个
2
×
3
×
5
×
7
×
11
×
13
×
17
×
19
×
23
×
29
×
31
>
2
×
1
0
9
2\times3\times5\times7\times11\times13\times17\times19\times23\times29\times31>2\times10 ^9
2×3×5×7×11×13×17×19×23×29×31>2×109
2.质因数指数之和不会超过31
最小质因数为2, 2 31 > 2 × 1 0 9 2^{31}>2\times10 ^9 231>2×109
6.代码
既然此时的数据不算大,我们完全可以通过暴力深搜来找结果。
同时我们的深搜要满足上面的几个条件:
1.枚举指数由30开始,自大而小;
2.仅枚举前十个质因数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int prim[]={2,3,5,7,11,13,17,19,23,29};
int sum=0,minx;
int n;
void dfs(int u,int x,ll a,int b){//当前质因数位置,剩余指数,当前值, 当前已有约数个数
if(b>sum||b==sum&&a<minx) {
sum=b;
minx=a;
}
for(int i=1;i<=x;i++){
if(a*prim[u]>n)break;
a*=prim[u];
dfs(u+1,i,a,b*(i+1));
}
}
int main(){
cin>>n;
// minx=INT_MAX;
dfs(0,30,1,1);
cout<<minx;
}