P1414 又是毕业季II

题目传送门

一、准备知识

求一个数x的所有约数

#include <bits/stdc++.h>

using namespace std;

const int N = 1010;
int c[N];

/**
 * 功能:获取指定数x的所有约数
 * @param x
 */
void ys(int x) {
    for (int i = 1; i <= sqrt(x); i++)
        //有约数
        if (x % i == 0) {
            c[i]++;  //i作为约数的次数++
            //记录另一个相对的约数
            //x!=i*i 防止记录重复,如果是完全平方,就记一个,这个是大的
            if (x != i * i) c[x / i]++;
        }
}

int main() {
    int x = 120;
    //获得所有的约数
    ys(x);
    for (int i = 1; i <= x; i++)
        for (int j = 1; j <= c[i]; j++) {
            cout << i;
            if (i < x) cout << "*";
        }

    return 0;
}

二、解题思路

思路:

\(i\)个数的公约数含义:\(i\)个数均含有某个约数,可以把所有数的约数全部求出来。

如果\(i\)个数均含有某个因数,那么这个因数必然是这\(i\)个数的公约数。

最大的就是它们的最大公约数。

总结:
1、\(1\)个数的最大公约数是它本身,这是本题给出的定义。下面的题解,也都是依照这个定义。

2、分解质因数+质因数个数 为\(c[N]\),\(0<=i<N\),\(i\)是指质因数,\(c[i]\)是指质因数\(i\)同现的次数。

3、想找出在\(n\)个数中选择\(i\)个数时的最大公约数,这意味着: \(1<=i<=n\)

  • \(c[m]>=i\) 其中\(m\)表示因子\(m\)出现的次数大于等于\(i\),选择了\(i\)个数字时,可能产生的公约数就是\(m\)

  • 那么,如何保证是最大呢?我们在计算每个数时,记录了最大约数\(m\),这是最大公约数的上限!

  • \(while\)循环,如果\(m\)的个数(\(c[m]\))小于\(i\),表示这个数字\(m\)无法成为\(i\)个数字的约数。减小\(1\)继续尝试。

当找到第一个符合条件的数字时,它就是最大公约数。

(3)、每增大一个\(i\),即选择的数字越多,最大公约数只可能不变或变小,不可能变大,所以\(m\)值可以继续复用。这里很巧妙!

三、C++代码

#include <bits/stdc++.h>

using namespace std;
const int N = 1e6 + 10;
int n;      //n个同学的能力值
int m;      //当前情况下可能的最大公约数
int c[N];   //每个约数i出现的次数c[i]

/**
 * 功能:获取指定数x的所有约数
 * @param x
 */
void ys(int x) {
    for (int i = 1; i <= sqrt(x); i++)
        //有约数
        if (x % i == 0) {
            c[i]++;  //i作为约数的次数++
            //记录另一个相对的约数
            //x!=i*i 防止记录重复,如果是完全平方,就记一个,这个是大的
            if (x != i * i) c[x / i]++;
        }
}

int main() {
    cin >> n;
    //读入n个能力值
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        m = max(m, x); //记录目前最大能力值
        //找出所有约数
        ys(x);
    }

    //在n个数中选择i个数字,求可能产生的最大公约数。
    for (int i = 1; i <= n; i++) {
        while (c[m] < i) m--;
        cout << m << endl;
    }
    return 0;
}
posted @ 2021-08-31 14:34  糖豆爸爸  阅读(65)  评论(0编辑  收藏  举报
Live2D