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;
}