zoukankan      html  css  js  c++  java
  • 题解 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;
    }
    
  • 相关阅读:
    mysql 性能监控
    拼接字符
    mysql 存储 2
    mysql 存储过程
    flock
    readfile() file_get_content f
    url_encode和base64
    jsdetox反混淆js内容,解密前端加密参数
    前端加密之使用firefox来解密
    v to ray做渗透测试
  • 原文地址:https://www.cnblogs.com/colazcy/p/12865309.html
Copyright © 2011-2022 走看看