跳转至

小团的装饰物#
发布于2021-04-16
上次编辑2021-04-16

问题描述#

小团正在装饰自己的书桌,他的书桌上从左到右有 m 个空位需要放上装饰物。商店中每个整数价格的装饰物恰好有一种,且每种装饰物的数量无限多。
小团去商店的时候,想到了一个购买方案,他要让右边的装饰物价格是左边的倍数。用数学语言来说,假设小团的 m 个装饰物价格为 a[1], a[2], ..., a[m] ,那么对于任意的 1≤i≤j≤m ,a[j] 是 a[i] 的倍数。
小团是一个节约的人,他希望最贵的装饰物不超过 n 元。现在,请你计算小团有多少种购买的方案?

格式:

输入:
- 输入包含两个数,n 和 m 。
输出:
- 输出一个数,结果对 998244353 取模,表示购买的方案数。

示例:

输入:4 2
输出:8
解释:[1,1][1,2][1,3][1,4][2,2][2,4][3,3][4,4] 共 8 种。

提示:

  • 对于 40% 的数据,n, m ≤ 10
  • 对于 100% 的数据,1 ≤ n, m ≤ 1000

解题思路#

方法一:动态规划#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int n, m, MOD = 998244353;
    cin >> n >> m;
    vector<int> dp(1 + n, 1);
    while (--m) {
        vector<int> tmp(1 + n);
        for (int i = n; i >= 1; --i) {
            for (int j = 1; i * j <= n; ++j) {
                tmp[i * j] = (1LL * tmp[i * j] + dp[i]) % MOD;
            }
        }
        swap(dp, tmp);
    }
    int ans = 0;
    for (int x : dp) {
        ans = (1LL * ans + x) % MOD;
    }
    cout << ans << '\n';
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios_base::sync_with_stdio(false), cin.tie(nullptr);
    int n, m, MOD = 998244353;
    cin >> n >> m;
    vector<vector<int>> fac(n + 1);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j * j <= i; ++j) {
            if (i % j == 0) {
                fac[i].emplace_back(j);
                if (j * j != i) {
                    fac[i].emplace_back(i / j);
                }
            }
        }
    }
    vector<vector<int>> memo(n + 1, vector<int>(m + 1));
    function<int(int, int)> dp = [&](int n, int m) {
        if (memo[n][m]) {
            return memo[n][m];
        }
        if (n == 1 || m == 1) {
            return 1;
        }
        int res = 0;
        for (int x : fac[n]) {
            res = (1LL * res + dp(x, m - 1)) % MOD;
        }
        return (memo[n][m] = res);
    };
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        ans = (1LL * ans + dp(i, m)) % MOD;
    }
    cout << ans << '\n';
    return 0;
}

方法二:#

实际上这道题来自 AtCoder C - Multiple Sequences,原题的范围是 \(1 \le N, M \le 2\times10^5\)

返回顶部

在手机上阅读