题目相关
题目链接
AtCoder Beginner Contest 169 D题,https://atcoder.jp/contests/abc169/tasks/abc169_d。
Problem Statement
Given is a positive integer N. Consider repeatedly applying the operation below on N:
- First, choose a positive integer z satisfying all of the conditions below:
- z can be represented as z=p^e, where p is a prime number and e is a positive integer;
- z divides N;
- z is different from all integers chosen in previous operations.
- Then, replace N with N/z.
Find the maximum number of times the operation can be applied.
Input
Input is given from Standard Input in the following format:
N
Output
Print the maximum number of times the operation can be applied.
Samples1
Sample Input 1
24
Sample Output 1
3
Explaination
We can apply the operation three times by, for example, making the following choices:
- Choose z=2(=2^1). (Now we have N=12.)
- Choose z=3(=3^1). (Now we have N=4.)
- Choose z=4(=2^2). (Now we have N=1.)
Samples2
Sample Input 2
1
Sample Output 2
0
Explaination
We cannot apply the operation at all.
Samples3
Sample Input 3
64
Sample Output 3
3
Explaination
We can apply the operation three times by, for example, making the following choices:
- Choose z=2(=2^1). (Now we have N=32.)
- Choose z=4(=2^2). (Now we have N=8.)
- Choose z=8(=2^3). (Now we have N=1.)
Samples4
Sample Input 4
1000000007
Sample Output 4
1
Explaination
We can apply the operation once by, for example, making the following choice:
- z=1000000007(=1000000007^1). (Now we have N=1.)
Samples5
Sample Input 5
997764507000
Sample Output 5
7
Constraints
- All values in input are integers.
- 1 ≤ N ≤ 10^12
题解报告
题目翻译
给一个正整数 N,对 N 按照以下规则进行重复操作:
- 第一,选择一个正整数 z,该数据满足以下条件:
- z 表示为 p^e,其中 p 是一个质数,e是一个正整数;
- 用 z 除 N;
- z 必须是唯一的.
- 接着,使用 N/z 的值替代 N。
要求我们找出这样操作方案的最大次数。
题目分析
熟悉的味道,质因数分解。由于题目中提到了最大,所以思路肯定是从最小开始,每个质因数每次取得越小越好。
数学讲解
根据题目的意思,我们可以写出这样的一个质因数分解式:,式中
表示i一个质数,
表示幂次。我们的任务就是找出
最大的整数。显然,最佳的情况就是即构成一个自然数等差序列:
。
,即
,那么 x 的取值为
或者
。
数据范围分析
1 ≤ N ≤ 10^12,超过了 int 的表示范围,因此需要使用 long long 或者 unsigned long long。
OI 知识点
1、质数判定。
2、质因数分解。
样例数据分析
样例数据 1
N = 24。首先根据题目给出的原则。
1、第一次:我们使用 z=2^1=2。因此 24/2=12。
2、第二次:我们使用 z=2^2=4。因此 12/4=3。
3、第三次:我们使用 z=3^1=3。因此 3/3=1。
这样,我们经过 3 次分解完成。
根据我们的数学分析,。
1、,因此,对于质数 2 来说,我们可以分解的次数为:
或者
,经过验算,为 2,即
。
2、,因此,对于质数 3 来说,我们可以分解的次数为:
或者
,经过验算,为 1,即
。
合计为:2+1=3 次。
样例数据 2
N = 1,没有可以质因数分解的。所以输出 0。
样例数据 3
N = 64。首先根据题目给出的原则。
1、第一次:我们使用 z=2^1=2。因此 64/2=32。
2、第二次:我们使用 z=2^2=4。因此 32/4=8。
3、第三次:我们使用 z=2^3=8。因此 8/8=1。
这样,我们经过 3 次分解完成。
根据我们的数学分析,。
1、,因此,对于质数 2 来说,我们可以分解的次数为:
或者
,经过验算,为 3,即
。
合计为 3 次。
样例数据 4
N = 1000000007。首先根据题目给出的原则。由于 1000000007 是质数。所以结果为 1。
样例数据 5
N = 997764507000。首先根据题目给出的原则。
1、第一次:我们使用 z=2^1=2。因此 997764507000/2=498882253500。
2、第二次:我们使用 z=2^2=4。因此 498882253500/4=124720563375。
3、第三次:我们使用 z=3^1=3。因此 124720563375/3=41573521125。
4、第四次:我们使用 z=3^2=9。因此 41573521125/9=4619280125。
5、第五次:我们使用 z=5^1=5。因此 4619280125/5=923856025。
6、第六次:我们使用 z=5^2=25。因此 923856025/25=36954241。
7、第七次:我们使用 z=6079^2=36954241。因此 36954241/36954241=1。
这样,我们经过 7 次分解完成。
根据我们的数学分析,。
1、,因此,对于质数 2 来说,我们可以分解的次数为:
或者
,经过验算,为 2,即
。
2、,因此,对于质数 3 来说,我们可以分解的次数为:
或者
,经过验算,为 2,即
。
3、,因此,对于质数 5 来说,我们可以分解的次数为:
或者
,经过验算,为 2,即
。
4、,因此,对于质数 6079 来说,我们可以分解的次数为:
或者
,经过验算,为 1,即
。
合计为:2+2+2+1=7 次。
算法设计
1、读入数据 n。
2、找出 n 以内的所有质数,以及对应的幂次数。比如 。
3、遍历找出答案。
AC 参考代码
提交的代码
当时在比赛的时候没有分析得这么清楚,在遍历可能性的时候,使用了枚举法,其实完全可以直接使用计算公式来完成。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
LL n;
cin>>n;
vector<pair<LL, int> > dvs;//配对<质数, 幂次>
//质因数分解
for (LL i=2; i*i<=n; i++) {
if (0==n%i) {
dvs.push_back(make_pair(i, 0));
while (0==n%i) {
dvs.back().second++;
n /= i;
}
}
}
if (n>1) {
dvs.push_back(make_pair(n, 1));
}
//遍历
int ans = 0;
for (pair<LL, int> &p : dvs) {
int i;
for (i=1; (i+1)*i/2<=p.second; i++);
i--;
ans += i;
}
cout << ans << endl;
return 0;
}
改进的代码
就是在遍历部分,可以直接计算。降低了时间。对算法的复杂度没有影响。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
LL n;
cin>>n;
vector<pair<LL, int> > dvs;//配对<质数, 幂次>
//质因数分解
for (LL i=2; i*i<=n; i++) {
if (0==n%i) {
dvs.push_back(make_pair(i, 0));
while (0==n%i) {
dvs.back().second++;
n /= i;
}
}
}
if (n>1) {
dvs.push_back(make_pair(n, 1));
}
//遍历
int ans = 0;
for (pair<LL, int> &p : dvs) {
int i=sqrt(p.second*2);
if (i*(i+1)>p.second*2) {
i--;
}
ans += i;
}
cout << ans << endl;
return 0;
}

本文深入解析AtCoderBeginnerContest169D题,通过质因数分解策略求解正整数N能被特定形式z=p^e分解的最大次数,详细分析了算法设计与代码实现。
482

被折叠的 条评论
为什么被折叠?



