数学结论【p1463】[POI2002][HAOI2007]反素数

Description

对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。

如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。例如,整数1,2,4,6等都是反质数。

现在给定一个数N,你能求出不超过N的最大的反质数么?

Input

一个数N(1<=N<=2,000,000,000)。

Output

不超过N的最大的反质数。

woc,神仙题.

一.暴力(O(n^{frac{5}{2}})) (40pts)

直接写暴力的话,可以(get)(40pts)

暴力怎么写?

直接倒叙枚举(n),再判断当前(i)是否满足条件.(再枚举一层(j))

这样

for(R int i=n;i;i--)
    {
        R int res=calc(i);
        bool flg=false;
        for(R int j=1;j<i;j++)
            if(res<=calc(j)){flg=true;break;}
        if(!flg)
        {
            printf("%d",i);
            break;
        }
    }

上面的(calc)函数是计算约数个数,(sqrt{n})的复杂度.

二,正解

还好突然想起来结论.

首先根据唯一分解定理

[x=p_1^{k_1} imes p_2^{k_2} imes p_3^{k_3} imes dots ]

这里的(p)全部都是质数.

然后结论就是.

[d(x)=(k_1+1) imes(k_2+1) imes dots ]

其实真正的定义的话,(d(x))代表(x)的约数个数.

因此搜索就好了,枚举每一个质数的(k)次方,记录答案.

需要注意的是,当某一个数的约数个数之前已经出现过,那我们要取较为靠前的一个.

(因为题目要求必须严格(>))

代码

#include<cstdio>
#include<cctype>
#define int long long
#define R register
#define N 10000008
using namespace std;
inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}
int prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};
int ans,mx,n;
void dfs(int dep,int now,int cnt)
{
	if(dep>=11)return;		
	if(cnt>mx)mx=cnt,ans=now;
	if(cnt==mx and ans>now)ans=now;
	for(R int i=1;i<=32;i++)
	{
		if(now*prime[dep]>n)break;
		dfs(dep+1,now*=prime[dep],cnt*(i+1));
	}
}
signed main()
{
	in(n);
	dfs(1,1,1);
	printf("%lld",ans);
}
原文地址:https://www.cnblogs.com/-guz/p/9845638.html