反素数 Antiprime(dfs)

反素数 Antiprime(dfs)

原题来自:POI 2001

如果一个大于等于 1 的正整数 n,满足所有小于 n 且大于等于 1 的所有正整数的约数个数都小于 n 的约数个数,则 n 是一个反素数。譬如:1, 2, 4, 6, 12, 24,它们都是反素数。

请你计算不大于 n 的最大反素数。

输入格式
一行一个正整数 n。

输出格式
只包含一个整数,即不大于 n 的最大反素数。

样例
Input

1000

Output
840

数据范围与提示
对于 10% 的数据,1≤n≤103

对于 40% 的数据,1≤n≤106

对于 100% 的数据,1≤n≤2×109

思路: 用到了唯一分解定理和因数个数定理

唯一分解定理:
任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积
N=p1^a1 * p2^a2 * p3^a3...这里p1<p2<p3<...<pn,且均为质数

因数个数定理:
还是上面那个式子,N的因数个数 = (a1+1) * (a2+1) * ... *(an+1);

反素数的本质就是尽可能地让因子数量最大,但是数值最小。

下面来解释一下这句话

以我们的题为例,求不大于n的最大反素数,令它为x:

  1. x一定是小于n的约数最多的数(根据定义很容易就能看出来)
  2. 约数个数相同时,x一定是最小的数(举个例子,a,b(a<b)的约数个数相同,若我们选取b为反素数,则会不满足f(a)<f(b),f(x)为x的因数个数,所以我们的x一定是最小的数)

那如何选取最小的数呢,指数递减即可

AC代码:

#include<stdio.h>
#include<string.h>
#define ll long long
#include<algorithm>
using namespace std;
ll n,maxx=0,ans=0;
//maxx记录总因数的最大值,ans记录对应的数值
ll p[11]={0,2,3,5,7,11,13,17,19,23,29};
//deep 当前枚举到第几个质数了
//cur 从开始到现在共有多少因数
//num 枚举到此组成的数
//up 当前质数的最大指数 
//n最大取到2e9,2*3*5*7*11*13*17*19*23>2e9,所以枚举到此即可
void dfs(ll deep,ll cur,ll num,ll up)
{
	if(deep>10) return ;
	if(cur>maxx||(cur==maxx&&num<ans))//目前因数总个数>maxx,或因数个数相等,数值较小,更新maxx,ans
	maxx=cur,ans=num;
	for(int i=1;i<=up;i++)//枚举
	{
		num*=p[deep];
		if(num>n) return ;
		dfs(deep+1,(i+1)*cur,num,i);
	 } 
}
int main()
{
	scanf("%lld",&n);
	dfs(1,1,1,31);
	//枚举从2开始,2^31 > 2e9
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值