题解 P1128 【[HNOI2001]求正整数】

题目链接

Solution [HNOI2001]求正整数

题目大意:给定一个(n),求质因子个数恰好为(n)的最小正整数

爆搜,对数优化高精度


因为如果一个数(n = prod_{i=1}^np_i^{k_i}),其质因子个数为(n = prod_{i=1}^n{(k_i+1)})

所以我们对给定的(n)进行因数分解,分解出来的每个因子(-1)后作为质数的指数,乘起来就是答案,可以爆搜

(ans = prod_{i=1}^np_i^{k_i})

(p_i)一定连续,否则将大质数替换为空缺小质数之后答案更优。其次(k_i)单调不升,否则将大指数放在小底数上答案更优

层数不会太多,假设(n)(2)的次幂,答案为若干质数乘积,最多(16)

关键优化:在(dfs)过程中进行(n^2)高精度乘法非常耗时,因为我们只关心大小,只在最后输出时需要准确值,因此可以只保存指数,取对数比较大小

(log(a^p)=p*log(a))

(log(ab)=log(a) + log(b))

(n = prod_{i=1}^np_i^{k_i})

(log(n) = sum_{i=1}^{n}k_i*log(p_i))

(假设底数相同,程序中直接取(e),多次对数运算耗时可先保存起来)

#include <cmath>
#include <cstdio>
#include <cstring> 
using namespace std;
typedef long long ll;
double lg[128];
int pri[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101};//26
struct BigInt{
	static const int siz = 32;
	unsigned int p[siz];
	BigInt(){
		for(int i = 0;i < 32;i++)p[i] = 0;
	}
	bool operator < (const BigInt &rhs)const{
		double a = 0,b = 0;
		for(int i = 0;i < siz;i++)a += p[i] * lg[pri[i]];
		for(int i = 0;i < siz;i++)b += rhs.p[i] * lg[pri[i]];
		return a < b;
	}
	bool operator == (const BigInt &rhs)const{
		for(int i = 0;i < siz;i++)
			if(p[i] != rhs.p[i])return false;
		return true;
	}
	bool operator > (const BigInt &rhs)const{
		return !(*this < rhs || *this == rhs);
	}
	BigInt operator * (const BigInt &rhs)const{
		BigInt res;
		for(int i = 0;i < siz;i++)res.p[i] = p[i] + rhs.p[i]; 
		return res;
	}
	inline void print(){
		for(int i = 0;i < siz;i++)
			printf("%d ",int(p[i]));
	}
};
struct Output{ 
	static const int size = 32768,base = 10000;
	unsigned int val[size],len;
	inline void maintain(int pos){
		val[pos + 1] += val[pos] / base;
		val[pos] %= base;
	}
	inline void clear(){
		for(int i = 0;i <= len;i++)val[i] = 0; 
	}
	Output():len(0){} 
	Output(long long v){
		len = 0;
		do{
			val[len++] = v % base;
			v /= base;
		}while(v);
	}
	Output operator * (const Output &rhs)const{
		Output res;
		res.len = this->len + rhs.len + 1;res.clear();
		for(int i = 0;i < this->len;i++)
			for(int j = 0;j < rhs.len;j++){
				res.val[i + j] += this->val[i] * rhs.val[j];
				res.maintain(i + j);
			}
		for(int i = 0;i <= len;i++)res.maintain(i); 
		while(!res.val[res.len - 1])res.len--;
		return res; 
	} 
	inline void print()const{
		printf("%d",val[len - 1]);
		for(int i = len - 2;i >= 0;i--)printf("%.4d",val[i]); 

	}
};
template <typename A,typename B>
inline A qpow(A a,B b){
	A res = 1,base = a;
	while(b){
		if(b & 1)res = res * base;
		base = base * base;
		b >>= 1;
	}
	return res;
}

BigInt ans,beg;
inline void dfs(BigInt nowans,int nownum,int last,int dep){
	if(nowans > ans)return;
	if(nownum == 1){
		ans = nowans;
		return;
	}
	for(int i = 2;i <= nownum;i++){
		if(last < i)continue;
		if(nownum % i)continue;
		BigInt nxt = nowans;
		nxt.p[dep] += i - 1;
		dfs(nxt,nownum / i,i,dep + 1);
	}
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i = 0;i < BigInt::siz;i++)ans.p[i] = 19260817;
	for(int i = 1;i < 128;i++)lg[i] = log(i);
	dfs(beg,n,0x7fffffff,0);
	Output ansout = 1;
	for(int i = 0;i < BigInt::siz;i++)if(ans.p[i])ansout = ansout * qpow(Output(pri[i]),ans.p[i]);
	ansout.print();
	return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/12865309.html