对于任何正整数x,其约数的个数记作 g ( x ) g(x) g(x)。例如g(1)=1,g(6)=4。
如果某个正整数x满足: ∀ 0 < i < x ∀ 0 < i < x \forall 0 \lt i \lt x∀0∀0<i<x∀0<i<x,都有 g ( x ) > g ( i ) g(x) \gt g(i) g(x)>g(i)则称x为反质数。例如,整数1,2,4,6等都是反质数。
现在给定一个数 N,你能求出不超过 NN 的最大的反质数么?
一个数N
不超过N的最大的反质数
1000
840
1 ≤ N ≤ 2 × 1 0 9 1≤N≤2×10^9 1≤N≤2×109
第一眼看上去:暴搜,倒着枚举,输出第一个反素数
第二眼:2e9
好吧,暴搜明显是会TLE的,所以我们只能换个思路
g(x)怎么求呢?枚举所有因数然后统计个数吗,太慢了
设 x = ∏ p i k i x=\prod p_i^{k_i} x=∏piki(质因数分解定理),则 g ( x ) = ∏ ( k i + 1 ) g(x)=\prod (k_i+1) g(x)=∏(ki+1)(乘法原理)
有些蒙?举个例子 6 = 2 1 ∗ 3 1 6=2^1*3^1 6=21∗31
6的约数是哪几个呢?
不难想到
2 0 ∗ 3 0 = 1 2^0*3^0=1 20∗30=1
2 1 ∗ 3 0 = 2 2^1*3^0=2 21∗30=2
2 0 ∗ 3 1 = 3 2^0*3^1=3 20∗31=3
2 1 ∗ 3 1 = 6 2^1*3^1=6 21∗31=6
一共有6个
细心的读者都发现了为什么 g ( x ) = ∏ ( k i + 1 ) g(x)=\prod (k_i+1) g(x)=∏(ki+1)是成立的
所以对于一个反素数x,假设 p i p_i pi是单调递增的,那么 k i k_i ki必须不升,否则将 k i k_i ki从大到小排序后,新的x一定比原来的小而且约数个数相等(想一想,为什么),那么原来的x就一定不是反素数了
还是有些蒙?举个例子 18 = 2 1 ∗ 3 2 18=2^1*3^2 18=21∗32
这里的 k i k_i ki是 1 , 2 1,2 1,2,可以看到并不是不升序列,所以我们将它从大到小排序 2 2 ∗ 3 1 = 12 2^2*3^1=12 22∗31=12
可以看到,此时得出的新x(12)的约数个数与原来的x(18)是相等的(在上面已经证明过),又根据反素数的定义
如果某个正整数x满足: ∀ 0 < i < x ∀ 0 < i < x \forall 0 \lt i \lt x∀0∀0<i<x∀0<i<x,都有 g ( x ) > g ( i ) g(x) \gt g(i) g(x)>g(i)则称x为反质数
得出18一定不是反素数
至于在将 k i k_i ki从大到小排序后,得出的数一定比原来的小,我们再举个例子
设 x 1 = p 1 k 1 p 2 k 2 , x 2 = p 1 k 2 p 2 k 1 ( k 1 < k 2 , p 1 < p 2 ) x_1=p_1^{k_1}p_2^{k_2},x2=p_1^{k_2}p_2^{k_1}(k_1
将 x 1 , x 2 x_1,x_2 x1,x2分别拆成 ( p 1 p 2 ) k 1 ∗ p 2 k 2 − k 1 ({p_1}{p_2})^{k_1}*{p_2}^{k_2-k_1} (p1p2)k1∗p2k2−k1和 ( p 1 p 2 ) k 1 ∗ p 1 k 2 − k 1 ({p_1}{p_2})^{k_1}*{p_1}^{k_2-k_1} (p1p2)k1∗p1k2−k1
两个数谁大谁小一目了然
因为前9个质数(2,3,5,7,11,13,17,19,23)乘积已经超过了 2 ∗ 1 0 9 2*10^9 2∗109,所以我们只需要枚举这9个质数的指数就可以找出所有能够成为反素数的数
理论存在,实践开始!
#include
using namespace std;
#define int long long
const int maxn=1e6+5;
int p[]={0,2,3,5,7,11,13,17,19,23,29};
int tot,n;
pair<int,int> a[maxn];//(i,g(i))
void dfs(int i,int last,int pi,int g){
//i表示搜到第几个质数
//last表示上一个质数的指数
//pi表示当前因数
//g表示当前答案的约数个数
a[++tot]=make_pair(pi,g);
if(i>9) return;
int pp=p[i];
for(int j=1;j<=last;j++){//不升序列
if(1ll*pi*pp>n) break;//若当前乘积超过n,那么直接退出循环
pi*=pp;
dfs(i+1,j,pi,g*(j+1));
}
}
signed main()
{
cin>>n;
dfs(1,100,1,1);//默认第一个质数必选(2的100次方已经很大了)
sort(a+1,a+1+tot);
int maxn=a[1].second,ans=a[1].first;
for(int i=2;i<=tot;i++) if(a[i].second>maxn) maxn=a[i].second,ans=a[i].first;
//筛一遍,保证找到的反素数是最大的
cout<<ans;
return 0;
}
完结撒花