Label
素数及因子相关性质+贪心
Description
设∀x∈N+\forall x\in N^+∀x∈N+,定义g(x)=∑i=1x[i∣x]g(x)=\sum_{i=1}^{x}[i|x]g(x)=∑i=1x[i∣x](即xxx的约数个数),若某个正整数xxx满足:∀0<i<x,g(x)>g(i)\forall 0<i<x,g(x)>g(i)∀0<i<x,g(x)>g(i),则称xxx为反质数。现给定一数N(1≤n≤2×109)N(1\leq n \leq 2\times 10^9)N(1≤n≤2×109),请求出不超过NNN的最大的反质数。
Solution
首先,根据素数的唯一分解定理,若将任意合数xxx改写为∏pici\prod p_i^{c_i}∏pici,那么根据乘法原理,易得其因子数为∏(ci+1)\prod(c_i+1)∏(ci+1)。
然后,我们考虑答案的构成:我们将任意正整数xxx分解为∏pici\prod p_i^{c_i}∏pici,那么为了让xxx的因子个数尽量多,我们应该避免“pip_ipi是较大的素数”这一情况的出现。进而,我们可以引出一个引理:
引理1:在此题数据范围下,答案一定可以表示成不超过9个最小的素数的乘积。
由于:
2×3×5×7×11×13×17×19×23=223,092,870<2×1092\times3\times5\times7\times11\times13\times17\times19\times23=223,092,870<2\times 10^92×3×5×7×11×13×17×19×23=223,092,870<2×109
2×3×5×7×11×13×17×19×23×29=6,469,693,230>2×1092\times3\times5\times7\times11\times13\times17\times19\times23\times 29=6,469,693,230>2\times 10^92×3×5×7×11×13×17×19×23×29=6,469,693,230>2×109
所以,若出现其它≥29\geq29≥29的素因子,其一定不如换做更小因子的答案更优。(相同因子个数的数的集合:最小的数才有可能是答案,详见最后)。
引理2:∑ci≤30\sum c_i\leq30∑ci≤30
证明:由于230<2×109,231>1092^{30}<2\times 10^9,2^{31}>10^{9}230<2×109,231>109,故∑ci≤30\sum c_i\leq30∑ci≤30
引理3:c1≥c2≥c3≥...≥cic_1\geq c_2\geq c_3\geq ...\geq c_ic1≥c2≥c3≥...≥ci
从贪心的角度出发,我们为了让各素数幂次积得到的数小一些,会让较小的素因子的次数大一些,故引理三肯定比其它情况优。
证明的话就是排序不等式的套路了,若存在微扰项(ci<ci+k)(c_i<c_{i+k})(ci<ci+k),那么将ci,ci+kc_i,c_{i+k}ci,ci+k交换后得到的数xxx肯定比原来的xxx小。
最后注意:对于约数相同的一组数,只有其中最小的一个数才有可能是答案(其余数均不满足反素数定义)
Summary
1、素数的唯一分解定理经常作为相关题目的切入角度,即经常把数字转化为素数之积来思考问题;
2、充分考虑特殊情况;
3、此题的相关结论比较经典,不失为不错的思考角度。
Code
#include<cstdio>
#include<iostream>
#define ri register int
#define ll long long
using namespace std;
int prime[11]={0,2,3,5,7,11,13,17,19,23,29};
int fstpower,cnt[11];
ll bits=1,n,maxn,ans,powprime[11][35];
void dfs(ll now,int power,int step)
{
if(step==11) return;
for(ri i=cnt[step-1];i>0;--i)
{
if(now*powprime[step][i]>n||powprime[step][i]==0) continue;
if(power*(i+1)>maxn||(power*(i+1)==maxn&&now*powprime[step][i]<ans&&now*powprime[step][i]>0))
//now*powprime[step][i]<ans:对于约数相同的一组数,
//只有其中最小的一个数才有可能是答案(其余数均不满足反素数定义)
{
maxn=power*(i+1);
ans=now*powprime[step][i];
}
cnt[step]=i;
if(step<10&&now*powprime[step][i]*prime[step+1]<=n)
dfs(now*powprime[step][i],power*(i+1),step+1);
}
}
void fst()
{
for(ri i=1;i<=n;++i)
{
if(bits*2>n) { fstpower=i-1; break; }
bits*=2;
}
for(ri i=1;i<=10;++i)
{
powprime[i][0]=1;
for(ri k=1;k<=fstpower;++k)
{
powprime[i][k]=powprime[i][k-1]*prime[i];
if(powprime[i][k]>=n) break;
}
}
}
int main()
{
scanf("%lld",&n);
fst();
cnt[0]=fstpower;
dfs(1,1,1);
cout<<ans;
return 0;
}