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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章