uva10791 Minimum Sum LCM(唯一分解定理)

来源:互联网 发布:装企叁度erp软件 编辑:程序博客网 时间:2024/04/27 21:44

题意描述:输入整数(n>=1&&n<2^31),求至少两个整数,使得他们的最小公倍数为n,且这些整数的和最小。输出最小和


解题思路:唯一分解定理

我们可以想象假如使整数和最小的且最小公倍数为n的数由x1,x2···,xm这些数组成,如果其中任意两个数有相同的约数,那么我们可以将其中一个除去约数,将使整体的和更小。因此可以肯定x1,x2···xm相互之间没有约数。将n转换为质数相乘的形式,可以发现当其中的每一个项作为一个x1,x2···xm中的一个数时能使整体和最小。因此我们可以把n运用唯一分解定理进行分解,将其中的每一项相加即可。

注意:

1、n的取值范围为2^31,因此我们只需要筛选出2^16 次方以内的素数即可,然后对n进行分解,如果分解结束后n>1,则证明现在的n是一个素数,而且这个素数大于2^16,且只有一次。因此将其加到结果上就行

2、如果分解后只有一项,我们需要对结果再加1,凑够两项

3、小心溢出的情况(2^31-1)


源代码:

#include <cstdio>#include <cmath>#include <cstring>#define MAXN 65536using namespace std;int prime[MAXN+1];int nprime;void getPrime(){    int m=sqrt(MAXN+0.5);    memset(prime,0,sizeof(prime));    for(int i=2;i<=m;++i) if(!prime[i])        for(int j=i*i;j<=MAXN;j+=i) prime[j]=1;    nprime=0;    for(int i=2;i<=MAXN;++i){        if(!prime[i])            prime[nprime++]=i;    }}int pows(int a,int b){    int tmp=1;    if(b==0)        return 1;    if(b==1)        return a;    tmp*=pows(a,b/2);    tmp*=tmp;    if(b%2)        tmp*=a;    return tmp;}int e[MAXN+1];long long getFactors(long long n){    memset(e,0,sizeof(e));    int cnt=0;    for(int i=0;i<nprime&&n>=prime[i];i++){        if(n%prime[i]==0)            cnt++;        while(n%prime[i]==0){            n/=prime[i];            e[i]++;        }        if(n==0||n==1)            break;    }    long long ans=0;    for(int i=0;i<nprime;i++){        if(e[i])            ans+=pows(prime[i],e[i]);    }    if(n>1){        ans+=n;        cnt++;    }    if(cnt==1)        return ans+1;    else        return ans;}long long n;int main(){    int cas=1;    getPrime();    while(scanf("%lld",&n)!=EOF&&n!=0){        printf("Case %d: ",cas);        if(n==1)            printf("2\n");        else            printf("%lld\n",getFactors(n));        cas++;    }    return 0;}



1 0