UVA 10791 最小公倍数的最小和

来源:互联网 发布:windows 8.1系统镜像 编辑:程序博客网 时间:2024/06/07 00:15

题意:

输入整数n,求至少两个正整数,使得它们的最小公倍数为n,且这些整数的和最小。输出最小的和。
参考:http://blog.csdn.net/mengxingyuanlove/article/details/47377657

题解:

我们可以想象假如使整数和最小的且最小公倍数为n的数由x1,x2···,xm这些数组成,如果其中任意两个数有相同的约数,那么我们可以将其中一个除去约数,将使整体的和更小。因此可以肯定x1,x2···xm相互之间没有约数。将n转换为质数相乘的形式,可以发现当其中的每一个项作为一个x1,x2···xm中的一个数时能使整体和最小。因此我们可以把n运用唯一分解定理进行分解,将其中的每一项相加即可。
注意:
1、n的取值范围为2^31,因此我们只需要筛选出2^16 次方以内的素数即可,然后对n进行分解,如果分解结束后n>1,则证明现在的n是一个素数,而且这个素数大于2^16,且只有一次。因此将其加到结果上就行
(分解质因数试除法,枚举到根号n即可)
2、如果分解后只有一项,我们需要对结果再加1,凑够两项
3、小心溢出的情况(2^31-1)
欧拉筛+快速幂+分解质因数

代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 65536;int e[maxn+1];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;}LL getFactors(LL 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==1) break;     }     LL 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;     return ans;}int main(){    int k=1;    LL n;    getPrime();    while(cin>>n&&n)    {      if(n==1) {printf("Case %d: %d\n",k++,2);continue;}      LL ans = getFactors(n);      printf("Case %d: %lld\n",k++,ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击