AtCoder题解——Beginner Contest 169——D - Div Game

题目相关

题目链接

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。

要求我们找出这样操作方案的最大次数。

题目分析

熟悉的味道,质因数分解。由于题目中提到了最大,所以思路肯定是从最小开始,每个质因数每次取得越小越好。

数学讲解

根据题目的意思,我们可以写出这样的一个质因数分解式:n=p_{0}^{q_{0}}*p_{1}^{q_{1}}*...*p_{x}^{q_{x}},式中 p_{i} 表示i一个质数,q_{i} 表示幂次。我们的任务就是找出 q_{i} 最大的整数。显然,最佳的情况就是即构成一个自然数等差序列:q_{i}=1+2+3+...+x

1+2+...+x=\frac{(x+1)*x}{2},即 x*(x+1)=2*q_{i},那么 x 的取值为 \sqrt{2*q_{i}} 或者 \sqrt{2*q_{i}}-1

数据范围分析

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 次分解完成。

根据我们的数学分析,24=2^{3}*3^{1}

1、q_{0}=3,因此,对于质数 2 来说,我们可以分解的次数为: \sqrt{2*3} 或者 \sqrt{2*3}-1,经过验算,为 2,即 \sqrt{2*3}

2、q_{1}=1,因此,对于质数 3 来说,我们可以分解的次数为: \sqrt{2*1} 或者 \sqrt{2*1}-1,经过验算,为 1,即 \sqrt{2*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 次分解完成。

根据我们的数学分析,64=2^{6}

1、q_{0}=6,因此,对于质数 2 来说,我们可以分解的次数为: \sqrt{2*6} 或者 \sqrt{2*6}-1,经过验算,为 3,即 \sqrt{2*6}

合计为 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 次分解完成。

根据我们的数学分析,997764507000=2^{3}*3^{3}*5^{3}*6079^{2}

1、q_{0}=3,因此,对于质数 2 来说,我们可以分解的次数为: \sqrt{2*3} 或者 \sqrt{2*3}-1,经过验算,为 2,即 \sqrt{2*3}

2、q_{1}=3,因此,对于质数 3 来说,我们可以分解的次数为: \sqrt{2*3} 或者 \sqrt{2*3}-1,经过验算,为 2,即 \sqrt{2*3}

3、q_{2}=3,因此,对于质数 5 来说,我们可以分解的次数为: \sqrt{2*3} 或者 \sqrt{2*3}-1,经过验算,为 2,即 \sqrt{2*3}

4、q_{3}=2,因此,对于质数 6079 来说,我们可以分解的次数为: \sqrt{2*2} 或者 \sqrt{2*2}-1,经过验算,为 1,即 \sqrt{2*2}-1

合计为:2+2+2+1=7 次。

算法设计

1、读入数据 n。

2、找出 n 以内的所有质数,以及对应的幂次数。比如 997764507000=2^{3}*3^{3}*5^{3}*6079^{2}

3、遍历找出答案。

AC 参考代码

提交的代码

当时在比赛的时候没有分析得这么清楚,在遍历可能性的时候,使用了枚举法,其实完全可以直接使用计算公式来完成。

#include 
using namespace std;

typedef long long LL;

int main() {
    LL n;
    cin>>n;

    vector > 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 &p : dvs) {
        int i;
        for (i=1; (i+1)*i/2<=p.second; i++);
        i--;
        ans += i;
    }

    cout << ans << endl;

    return 0;
}

改进的代码

就是在遍历部分,可以直接计算。降低了时间。对算法的复杂度没有影响。

#include 
using namespace std;

typedef long long LL;

int main() {
    LL n;
    cin>>n;

    vector > 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 &p : dvs) {
        int i=sqrt(p.second*2);
        if (i*(i+1)>p.second*2) {
            i--;
        }
        ans += i;
    }

    cout << ans << endl;

    return 0;
}

 

你可能感兴趣的:(OJ题解,#,AtCoder题解)