bdfz_2024_summer/day12/U466180/chat.md
2024-08-14 16:45:04 +08:00

2.9 KiB
Raw Blame History

这道题的目标是找到一个子序列使得该子序列中的所有元素都可以被某个大于1的整数$k$整除,并且该子序列的和最大。要实现这一点,我们可以考虑以下思路:

思路解析

  1. 选择质数作为$k$
    对于每一个质数$k$,如果序列中的所有元素都是$k$的倍数,那么这个子序列显然是合法的。因此,我们的目标就是找到一个质数$k$,使得从原序列中取出的所有$k$的倍数之和最大。

  2. 枚举质数$k$
    由于$k$必须是一个大于1的整数所以我们只需要枚举所有可能的质数$k$,并计算原序列中所有是$k$倍数的元素之和。然后取这些和中的最大值作为结果。

  3. 复杂度分析:
    由于题目给出的$ a_i 最大可以达到 10^9 $,所以质数的范围实际上是受限的。质数的个数大约为$O(\sqrt{a_i})$,因此枚举所有质数的复杂度是可以接受的。对于每个质数$k$,我们需要遍历整个序列以找到所有的$k$倍数,最终复杂度为$O(n\sqrt{a_i})$。

实现步骤

  1. 筛选质数:
    使用埃氏筛法或者其他方法来筛选出$[2,\sqrt{10^9}]$范围内的所有质数。

  2. 计算每个质数对应的合法子序列的和:
    对于每个筛选出的质数$k$,遍历原序列$ a_1, a_2, \dots, a_n $,计算其中所有是$k$倍数的元素的和。

  3. 取最大值:
    在所有质数对应的和中取一个最大值作为结果输出。

代码实现

以下是该思路的一个简单实现:

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAX_N = 1000;
const int MAX_A = 1e9;

// 埃氏筛法生成质数
vector<int> sieve(int limit) {
    vector<bool> is_prime(limit + 1, true);
    vector<int> primes;
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i <= limit; ++i) {
        if (is_prime[i]) {
            primes.push_back(i);
            for (int j = i * 2; j <= limit; j += i) {
                is_prime[j] = false;
            }
        }
    }
    return primes;
}

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    int sqrt_max_a = sqrt(MAX_A);
    vector<int> primes = sieve(sqrt_max_a);

    int max_sum = 0;

    // 枚举质数
    for (int p : primes) {
        int current_sum = 0;
        for (int i = 0; i < n; ++i) {
            if (a[i] % p == 0) {
                current_sum += a[i];
            }
        }
        max_sum = max(max_sum, current_sum);
    }

    cout << max_sum << endl;

    return 0;
}

进一步优化

在实际实现中,还可以考虑跳过不必要的计算,尤其是当发现某个质数的倍数已经产生很大和时,可以终止不必要的继续计算。此外,如果序列中的元素全部为质数,则可以直接跳过筛选质数的步骤,只计算质数本身。