UVA 10791 最小公倍数的最小和

题意:

输入整数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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值