1. 程式人生 > >數論_質數_BZOJ1053_反質數

數論_質數_BZOJ1053_反質數

點此開啟題目頁面

思路分析:

    可以證明, 以下結論1, 2, 3成立.

    結論1: 不超過N的最大的反質數為2...N中具有最多約數的最小的數(直接根據反質數定義即可證明此結論)

    結論2: 當N <= 2000000000時, N的不同質因數的個數不超過10(根據最小的11個質數的乘積為2\times 3\times 5\times 7\times 11\times 13\times 17\times 19\times 23\times 29\times 31>2000000000可證明此結論)

    結論3: 將不超過N的最大的反質數A分解質因數後滿足A = p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{n}^{c_{n}}, p_{i}<p_{i + 1}, c_{i}>=c_{i + 1}(參考氣泡排序交換的過程, 對於任意不滿足c_{i}

非遞增的A的分解形式, 均可通過若干次交換相鄰次冪使得c_{i}非遞增, 且每次交換均不減少A的約數個數且不增大A的值)

    下面給出基於結論1, 2, 3的AC程式碼:

//BZOJ1053_反素數
#include <iostream>
#include <vector> 
#include <algorithm>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
const int arr[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
int N; int resval, respow;// resval: 反素數值, respow: resval約數的個數
//path.first:質因數值, path.second: 冪次, mul: path中元素的乘積 
void dfs(vector<pii> &path, int mul){ 
	if(mul * 2ll > N){//注意此處應使用2ll, 直接用int型2會超出int的最大值 
		int cnt = 1; for(int i = 0; i < path.size(); ++i) cnt *= path[i].se + 1;
		if(cnt == respow) resval = min(resval, mul);
		else if(cnt > respow) respow = cnt, resval = mul;
		return;
	}
	for(int i = 0; i < 10; ++i)
		if(path.empty() || arr[i] > path.back().fi)
			for(long long j = 1, p = arr[i]
			    ; p * mul <= N && (path.empty() || path.back().se >= j); ++j, p *= arr[i])
				path.push_back(mp(arr[i], j)), dfs(path, p * mul), path.pop_back();
} 
int main(){
	cin >> N; vector<pii> vec; dfs(vec, 1), cout << resval << endl;
	return 0;
}