题意:
输入整数n,求至少两个正整数,使得它们的最小公倍数为n,且这些整数的和最小。输出最小的和。
参考:http://blog.youkuaiyun.com/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;
}