ABC 169D Div Game 题解 - 质因数分解+贪心

23 篇文章 0 订阅

题目链接

题目大意

给出一个正整数 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) (1im),我们要把 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) (1im),将 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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值