解题思路

  1. 这是一个动态规划问题,需要计算满足条件的数列个数
  2. 定义 表示长度为 且最后一个数字为 的合法数列个数
  3. 对于每个位置,我们需要:
    • 统计前一个位置所有数字的方案总和
    • 减去不满足条件的方案数(即对于当前数 ,减去所有是 倍数位置的方案数)
  4. 最终答案是最后一行所有位置的方案数之和
  5. 由于答案可能很大,需要对 取模

代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    const int mod = 1000000007;
    
    // dp[i][j]表示长度为i+1且最后一个数字为j的合法数列个数
    vector<vector<int>> dp(n, vector<int>(k+5, 0));
    
    // 初始化长度为1的情况
    for (int i = 1; i <= k; ++i)
        dp[0][i] = 1;
        
    // 动态规划过程
    for (int i = 1; i < n; ++i) {
        // 计算前一行的和
        int sum = 0;
        for (int j = 1; j <= k; ++j) {
            sum = (sum + dp[i-1][j]) % mod;
        }
        
        // 对每个数字计算当前位置的方案数
        for (int j = 1; j <= k; ++j) {
            dp[i][j] = sum;
            // 减去不满足条件的情况
            for (int mul = j*2; mul <= k; mul += j) {
                dp[i][j] = (dp[i][j] - dp[i-1][mul] + mod) % mod;
            }
        }
    }
    
    // 计算最终答案
    int ans = 0;
    for (int i = 1; i <= k; ++i) {
        ans = (ans + dp[n-1][i]) % mod;
    }
    
    cout << ans << endl;
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        final int mod = 1000000007;
        
        int[][] dp = new int[n][k+5];
        
        // 初始化
        for (int i = 1; i <= k; ++i)
            dp[0][i] = 1;
            
        // 动态规划
        for (int i = 1; i < n; ++i) {
            int sum = 0;
            for (int j = 1; j <= k; ++j) {
                sum = (sum + dp[i-1][j]) % mod;
            }
            
            for (int j = 1; j <= k; ++j) {
                dp[i][j] = sum;
                for (int mul = j*2; mul <= k; mul += j) {
                    dp[i][j] = ((dp[i][j] - dp[i-1][mul]) % mod + mod) % mod;
                }
            }
        }
        
        // 计算结果
        int ans = 0;
        for (int i = 1; i <= k; ++i) {
            ans = (ans + dp[n-1][i]) % mod;
        }
        
        System.out.println(ans);
    }
}
def solve(n, k):
    mod = 1000000007
    dp = [[0] * (k+5) for _ in range(n)]
    
    # 初始化
    for i in range(1, k+1):
        dp[0][i] = 1
        
    # 动态规划
    for i in range(1, n):
        # 计算前一行的和
        sum_prev = sum(dp[i-1][j] for j in range(1, k+1)) % mod
        
        # 计算当前行
        for j in range(1, k+1):
            dp[i][j] = sum_prev
            # 减去不满足条件的情况
            mul = j * 2
            while mul <= k:
                dp[i][j] = (dp[i][j] - dp[i-1][mul]) % mod
                mul += j
    
    # 计算最终答案
    ans = sum(dp[n-1][i] for i in range(1, k+1)) % mod
    return ans

n, k = map(int, input().split())
print(solve(n, k))

算法及复杂度

  • 算法:动态规划
  • 时间复杂度: - 对于每个位置需要处理 个数,每个数需要检查其倍数
  • 空间复杂度: - 需要二维dp数组存储状态