题目大意
给出一个正整数
n
n
n,并对它进行若干次操作
对于每次操作,选择一个正整数
x
x
x,满足
x
=
p
e
x=p^e
x=pe 且
x
x
x 跟其他操作中用过的
x
x
x 不一样(每个
x
x
x 只能用一次)。其中
p
p
p 为质数,
e
e
e 为正整数
将
n
n
n 变成
n
x
\frac{n}{x}
xn
问最多可以进行多少次这样的操作
首先,我们对
n
n
n 进行质因数分解,复杂度
O
(
n
)
\operatorname{O}(\sqrt{n})
O(n)
则
n
n
n 就可以表示为
p
1
e
1
×
p
2
e
2
×
⋯
×
p
m
e
m
p_{1}^{e_1} \times p_{2}^{e_2} \times \dots \times p_{m}^{e_m}
p1e1×p2e2×⋯×pmem
对于所有 ( 1 ≤ i ≤ m ) (1 \le i \le m) (1≤i≤m),我们要把 p i e i p_i^{e_i} piei 拆成 a 1 × a 2 × ⋯ × a k a_1 \times a_2 \times \dots \times a_k a1×a2×⋯×ak,满足所有 a a a 都是 p i p_i pi 的正整数次幂,使得不相同的 a i a_i ai 的个数最大
由于所有
a
i
a_i
ai 都是同底的,所以,上面的问题可以转化:
对于所有
(
1
≤
i
≤
m
)
(1 \le i \le m)
(1≤i≤m),将
e
i
e_i
ei 拆成若干个正整数之和,使得不同的数的个数最大,用贪心/背包实现即可
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const long long Maxn=60,Maxm=1000000+10;
long long f[Maxn],n,m,ans;
bool vis[Maxm];
inline long long read()
{
long long s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
long long dp(long long cnt) // 这里写的是背包
{
memset(f,0,sizeof(f)); // f[i] 表示 i 最多可以拆成出多少个不同的正整数
for(long long i=1;i<=cnt;++i)
for(long long j=cnt;j>=i;--j)
f[j]=max(f[j],f[j-i]+1);
return f[cnt];
}
bool check(long long x)
{
if(x==1)return 0; // O(sqrt(n)) 判断质数
for(long long i=2;i*i<=x;++i)
if(x%i==0)return 0;
return 1;
}
int main()
{
// freopen("in.txt","r",stdin);
n=read();
for(long long i=2;i*i<=n;++i)
{
if(vis[i])continue;
for(long long j=(i<<1);j*j<=n;j+=i)
vis[j]=1;
} // 筛素数
vis[1]=1,dp(55),m=n;
while(n!=1) // 一边质因数分解一边计算
{
for(long long i=2;i*i<=n;++i)
{
if(n%i || vis[i])continue;
long long cnt=0;
while(m%i==0 && m)++cnt,m/=i;
long long tmp=f[cnt];
ans+=tmp;
}
if(n==m)break;
n=m;
}
if(check(n))++ans;
printf("%lld\n",ans);
return 0;
}