题目链接:http://codeforces.com/contest/1062/problem/B
题意:给出n,有两种操作:
- 令n=sqrt(n);
- 令n=n*x;这里x是任意正整数。
问最少经过多少次操作可以使得n达到一个可以达到的最小值。输出最小值和最小操作次数。
解析:先将n分解质因子,假设n=p1^a1*p2^a2*...*pk^ak。观察操作1和操作2,发现n能达到的最小值就是p1*p2*...*pk;
再求最小次数过程重复如下:
- 如果a1、a2......ak都是2的倍数,那么执行sqrt操作,即将所有幂都除2,答案此时+1;
- 否则找最小的t,满足2^t刚好大于所有ai,此时答案+t+1(+1表示乘以任意正整数x,使得所有质因子的幂均变为2^t;+res表示sqrt操作k次)。这就是最终答案退出即可;
代码(31ms):
#include<iostream>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
ll pow2[105];//预处理2的幂
void init()
{
for(int i=0;i<=32;i++)
pow2[i]=1ll<<i;
}
ll len,p[105],num[105];
//len是质因子个数,p[i]是第i个质因子,num[i]是第i个质因子的个数
void init_n(ll n)//分解质因子
{
len=0;
for(ll i=2;i*i<=n;i++)
{
if(n%i==0)
{
p[++len]=i;
num[len]=0;
}
while(n%i==0)
{
num[len]++;
n=n/i;
}
}
if(n>1)
{
p[++len]=n;num[len]=1;
}
}
ll cal(ll x)//计算2的几次幂大于等于x
{
for(ll i=0;i<=32;i++)
if(pow2[i]>=x) return i;
return 0;
}
int main()
{
init();
ll n;cin>>n;
if(n==1)
{
cout<<1<<" "<<0<<endl;
return 0;
}
init_n(n);
ll ans1=1;
for(int i=1;i<=len;i++)
ans1=ans1*p[i];
ll ans2=0;
while(1)
{
bool f=true;
for(int i=1;i<=len;i++)
if(num[i]%2!=0){f=false;break;}
if(f)//如果所有质因子的幂都是2的倍数,那么执行sqrt操作,即将所有幂都除2
{
for(int i=1;i<=len;i++)
num[i]=num[i]/2;
ans2++;
}
else
{
ll res=0;
for(int i=1;i<=len;i++)//否则找最小的k,满足2^k刚好大于所有质因子的幂
{
res=max(res,cal(num[i]));
}
if(res==0) break;
ans2=ans2+res+1;//+1表示乘以x,使得所有质因子的幂均变为2^k;+res表示sqrt操作k次
break;
}
}
cout<<ans1<<" "<<ans2<<endl;
return 0;
}