小C的连续自然数乘积问题 | 豆包MarsCode AI 刷题

68 阅读4分钟

小C的连续自然数乘积问题 | 豆包MarsCode AI 刷题

在数学中,素数因子的分解是一个重要的概念。小S希望在 ([1, n]) 的范围内找到一些连续的自然数,这些数的乘积最多包含 ( k ) 个不同的素因子。你的任务是帮助小S找到可以取的连续自然数的最大长度。本文将探讨如何实现这一目标,并提供详细的代码实现。

问题描述

给定一个整数 ( n ) 和一个整数 ( k ),在 ([1, n]) 的范围内找到一些连续的自然数,这些数的乘积最多包含 ( k ) 个不同的素因子。目标是帮助小S找到可以取的连续自然数的最大长度。

解决方案

为了帮助小S找到可以取的连续自然数的最大长度,我们可以分以下几个步骤来实现:

  1. 素数筛选
    • 使用埃拉托斯特尼筛法(Sieve of Eratosthenes)生成 ([1, n]) 范围内的所有素数。
  2. 素因子分解
    • 对于每个数,记录其所有素因子。
  3. 滑动窗口
    • 使用滑动窗口技术,维护一个窗口内的不同素因子数量。
    • 当窗口内的不同素因子数量超过 ( k ) 时,移动窗口的左边界,直到窗口内的不同素因子数量不超过 ( k )。
    • 记录窗口的最大长度。

代码实现

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class Main {
    public static int solution(int n, int k) {
        boolean[] sieve = new boolean[n + 1];
        for (int i = 0; i < sieve.length; i++) {
            sieve[i] = true;
        }
        sieve[0] = false;
        sieve[1] = false;
        
        // 素数筛选
        for (int i = 2; i <= Math.sqrt(n); i++) {
            if (sieve[i]) {
                for (int j = i * i; j <= n; j += i) {
                    sieve[j] = false;
                }
            }
        }
        
        ArrayList<Integer> primes = new ArrayList<>();
        for (int i = 0; i < sieve.length; i++) {
            if (sieve[i]) {
                primes.add(i);
            }
        }
        
        ArrayList<Integer>[] factors = new ArrayList[n + 1];
        for (int i = 0; i < factors.length; i++) {
            factors[i] = new ArrayList<>();
        }
        
        // 素因子分解
        for (int prime : primes) {
            for (int multiple = prime; multiple <= n; multiple += prime) {
                factors[multiple].add(prime);
            }
        }
        
        int left = 1;
        int maxLength = 0;
        Map<Integer, Integer> primeCounts = new HashMap<>();
        int distinctPrimes = 0;
        
        // 滑动窗口
        for (int right = 1; right <= n; right++) {
            for (int p : factors[right]) {
                primeCounts.put(p, primeCounts.getOrDefault(p, 0) + 1);
                if (primeCounts.get(p) == 1) {
                    distinctPrimes++;
                }
            }
            
            while (distinctPrimes > k && left <= right) {
                for (int p : factors[left]) {
                    int count = primeCounts.get(p);
                    if (count == 1) {
                        primeCounts.remove(p);
                        distinctPrimes--;
                    } else {
                        primeCounts.put(p, count - 1);
                    }
                }
                left++;
            }
            
            int currentLength = right - left + 1;
            if (currentLength > maxLength) {
                maxLength = currentLength;
            }
        }
        
        return maxLength;
    }
    public static void main(String[] args) {
        // 测试样例
        System.out.println(solution(10, 3) == 6);  // 输出:true
        System.out.println(solution(20, 5) == 12);  // 输出:true
        System.out.println(solution(100, 4) == 10);  // 输出:true
    }
}

代码解释

  1. 素数筛选
    • 使用埃拉托斯特尼筛法生成 ([1, n]) 范围内的所有素数。
    • 初始化一个布尔数组 sieve,默认所有数为素数。
    • 从2开始,标记所有素数的倍数为非素数。
  2. 素因子分解
    • 对于每个数,记录其所有素因子。
    • 使用一个二维数组 factors,其中 factors[i] 存储 i 的所有素因子。
  3. 滑动窗口
    • 使用滑动窗口技术,维护一个窗口内的不同素因子数量。
    • 使用一个哈希表 primeCounts 记录窗口内每个素因子的出现次数。
    • 当窗口内的不同素因子数量超过 ( k ) 时,移动窗口的左边界,直到窗口内的不同素因子数量不超过 ( k )。
    • 记录窗口的最大长度。

测试样例

  • 样例1n = 10, k = 3,输出:6
    • 解释:在 ([1, 10]) 范围内,最长的连续自然数乘积最多包含3个不同素因子的子数组是 ([5, 6, 7, 8, 9, 10])。
  • 样例2n = 20, k = 5,输出:12
    • 解释:在 ([1, 20]) 范围内,最长的连续自然数乘积最多包含5个不同素因子的子数组是 ([9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])。
  • 样例3n = 100, k = 4,输出:10
    • 解释:在 ([1, 100]) 范围内,最长的连续自然数乘积最多包含4个不同素因子的子数组是 ([7, 8, 9, 10, 11, 12, 13, 14, 15, 16])。 通过上述方法,我们可以有效地帮助小S找到可以取的连续自然数的最大长度,确保在 ([1, n]) 范围内,连续自然数的乘积最多包含 ( k ) 个不同的素因子。