Acwing198 反素数 (思维+暴搜)

题目链接:https://www.acwing.com/problem/content/description/200/

题目大意:
给出一个正整数n,求不超过n的最大反素数。
反素数:g(x) > g(i) (1 < x <x), g(x):表示他的约数的个数

解题过程:
刚开始拿到这道题目的时候,我的第一反应是取寻找怎样才能找到一个反素数,我想了很久没想出来。
但是,我在尝试的过程中发现了一个现象,存在一些数字的约数的个数是一样多的,那么我想最大的反素数会不会就是这个范围内里拥有最多约数的数,并且这个数是拥有相同个数约数中最小的那个数字。
我们可以反证法,如果这个数字x不是最大的反素数,由于这已经是最小的那个拥有最多约数的数了,所以如果这个数字不是我们所需要的答案,那么真正的答案一定会大于这个数字,但是,如果答案真的是y > x,那么这就矛盾了因为g(y) = g(x) ,x < y。矛盾了,证毕。
所以这道题目想要我们求得其实就是拥有最多约数得那个且数值最小得数字。
然后接下来得问题,就是如何找到这个数字,通过质数得分解,我们知道约数计算得公式,所以倘若一个数字是答案,纳闷这个数字一定会拥有者尽量小得质数得因子,所以我们可以先去计算一下多少个质数会超过范围,后面发现从2开始的乘到第9个数字就已经是极限了,然后还有一个性质,数值大的质数的次数一定会小于等于数值小的质数。而最小的质数2最高的次数是30;
所以,我们发现其实这就是9个质数每个选多少个的问题,并且有了这些限制条件,我想到可以直接用搜索来写,由于可以剪枝,所以应该是可以过的,所以我进行了尝试,调试了一会儿,AC了。

代码一份:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

LL n, fi_number, fi_sum;
int prime[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23};

inline void dfs(int u, int max_u, LL sum, LL number) {
	if(number > fi_number || number == fi_number && sum < fi_sum) {
		fi_number = number;
		fi_sum = sum;
	}
	
	if(u == 9) return;
	
	for(int i = 1; i <= max_u; i ++) {
		if(sum * prime[u] > n) break;
		
		//选择当前一个质数
		sum = sum * prime[u];
		dfs(u + 1, i, sum, number * (i + 1)); 
	}
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	scanf("%lld", &n);
	fi_number = fi_sum = 1;
	dfs(0, 30, 1, 1);   //第几个质数,当前质数的数量限制,当前达到的数字,目前约数的个数 
	
	printf("%lld\n", fi_sum);
	
	return 0;
}
发布了179 篇原创文章 · 获赞 1 · 访问量 7582

猜你喜欢

转载自blog.csdn.net/weixin_42596275/article/details/104334996