P1463 [POI2001] [HAOI2007] 反素数

题目

题目描述

对于任何正整数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 1N2×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=2131
6的约数是哪几个呢?
不难想到
2 0 ∗ 3 0 = 1 2^0*3^0=1 2030=1
2 1 ∗ 3 0 = 2 2^1*3^0=2 2130=2
2 0 ∗ 3 1 = 3 2^0*3^1=3 2031=3
2 1 ∗ 3 1 = 6 2^1*3^1=6 2131=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=2132
这里的 k i k_i ki 1 , 2 1,2 1,2,可以看到并不是不升序列,所以我们将它从大到小排序 2 2 ∗ 3 1 = 12 2^2*3^1=12 2231=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_1x1=p1k1p2k2,x2=p1k2p2k1(k1<k2,p1<p2)
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)k1p2k2k1 ( 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)k1p1k2k1
两个数谁大谁小一目了然
因为前9个质数(2,3,5,7,11,13,17,19,23)乘积已经超过了 2 ∗ 1 0 9 2*10^9 2109,所以我们只需要枚举这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;
}

end

完结撒花

你可能感兴趣的:(算法,深度优先,图论)