P1463 [POI2002/HAOI2007]反素数

该博客探讨了反质数的概念,即在一定范围内找到因子个数最多的正整数。利用素数的唯一分解定理和贪心策略,证明了答案可以表示为不超过9个最小素数的乘积,并通过动态规划求解最大反质数。文章总结了相关结论和代码实现,强调了数学思维和特殊情况的考虑在解题中的重要性。
摘要由CSDN通过智能技术生成
Label

素数及因子相关性质+贪心

Description

∀ x ∈ N + \forall x\in N^+ xN+,定义 g ( x ) = ∑ i = 1 x [ i ∣ x ] g(x)=\sum_{i=1}^{x}[i|x] g(x)=i=1x[ix](即 x x x的约数个数),若某个正整数 x x x满足: ∀ 0 < i < x , g ( x ) > g ( i ) \forall 0<i<x,g(x)>g(i) 0<i<x,g(x)>g(i),则称 x x x为反质数。现给定一数 N ( 1 ≤ n ≤ 2 × 1 0 9 ) N(1\leq n \leq 2\times 10^9) N(1n2×109),请求出不超过 N N N的最大的反质数。

Solution

首先,根据素数的唯一分解定理,若将任意合数 x x x改写为 ∏ p i c i \prod p_i^{c_i} pici,那么根据乘法原理,易得其因子数为 ∏ ( c i + 1 ) \prod(c_i+1) (ci+1)

然后,我们考虑答案的构成:我们将任意正整数 x x x分解为 ∏ p i c i \prod p_i^{c_i} pici,那么为了让 x x x的因子个数尽量多,我们应该避免“ p i p_i pi是较大的素数”这一情况的出现。进而,我们可以引出一个引理:

引理1:在此题数据范围下,答案一定可以表示成不超过9个最小的素数的乘积。

由于:

2 × 3 × 5 × 7 × 11 × 13 × 17 × 19 × 23 = 223 , 092 , 870 < 2 × 1 0 9 2\times3\times5\times7\times11\times13\times17\times19\times23=223,092,870<2\times 10^9 2×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 × 1 0 9 2\times3\times5\times7\times11\times13\times17\times19\times23\times 29=6,469,693,230>2\times 10^9 2×3×5×7×11×13×17×19×23×29=6,469,693,230>2×109

所以,若出现其它 ≥ 29 \geq29 29的素因子,其一定不如换做更小因子的答案更优。(相同因子个数的数的集合:最小的数才有可能是答案,详见最后)。

引理2: ∑ c i ≤ 30 \sum c_i\leq30 ci30

证明:由于 2 30 < 2 × 1 0 9 , 2 31 > 1 0 9 2^{30}<2\times 10^9,2^{31}>10^{9} 230<2×109,231>109,故 ∑ c i ≤ 30 \sum c_i\leq30 ci30

引理3: c 1 ≥ c 2 ≥ c 3 ≥ . . . ≥ c i c_1\geq c_2\geq c_3\geq ...\geq c_i c1c2c3...ci

从贪心的角度出发,我们为了让各素数幂次积得到的数小一些,会让较小的素因子的次数大一些,故引理三肯定比其它情况优。

证明的话就是排序不等式的套路了,若存在微扰项 ( c i < c i + k ) (c_i<c_{i+k}) (ci<ci+k),那么将 c i , c i + k c_i,c_{i+k} ci,ci+k交换后得到的数 x x x肯定比原来的 x x x小。

最后注意:对于约数相同的一组数,只有其中最小的一个数才有可能是答案(其余数均不满足反素数定义)

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值