1.可构造的序列总数
问题描述
构造王国一年一度的构造大赛又开始了,这次构造王国的国王将只给定两个数字k和n,需要大家回答出能构造多少个符合以下条件的序列:
·序列的长度为n。
·1≤a₁≤a₂≤a₃≤……≤an≤k。
·Qi是aj-1的倍数(i≥2)。
由于答案可能非常大,你需要对10⁹+7取模。
输入格式
输入一行包括两个空格分隔的整数k和n。数据范围保证:1≤n,k≤2000。
输出格式
输出一个整数表示答案,答案需要对10⁹+7取模。
样例输入
22
样例输出
3
说明
样例中符合条件的序列有[1,1],[1,2],[2,2]总共三种。
我的答案:
一、信息
- 输入:两个整数
k
和n
,分别代表序列中元素的最大值和序列长度。 - 输出:满足条件的序列数量,对
10^9 + 7
取模。
二、分析
信息作用
我们需要生成长度为 n
的序列,其中序列中的每个元素都不超过 k
,且满足给定的条件。
思考和分析过程
- 考虑使用动态规划求解问题。
- 定义
dp[i][j]
为长度为i
且最大元素为j
的序列数量。 - 由于
a_i
应该是a_{i-1}
的倍数,我们需要统计所有可能的a_{i-1}
使得j
是a_{i-1}
的倍数。
题目样例分析
- 输入:
k=2, n=2
。 - 输出:
3
,符合条件的序列有[1,1]
,[1,2]
, 和[2,2]
。
三、算法设计
- 动态规划:
- 初始化
dp[1][j] = 1
对于所有1 ≤ j ≤ k
,因为长度为 1 的序列只有自身。 - 对于每个
i
从2
到n
,遍历每个j
从1
到k
,然后计算dp[i][j]
:dp[i][j]
等于所有dp[i-1][m]
的和,其中m
是j
的因子。
- 计算长度为
n
的序列总数为所有dp[n][j]
的和。
- 初始化
四、代码实现(C++)
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;
int main() {
int k, n;
cin >> k >> n;
vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
// 初始化长度为1的序列的数量
for (int j = 1; j <= k; ++j) {
dp[1][j] = 1;
}
// 填充 dp 表
for (int i = 2; i <= n; ++i) {
for (int j = 1; j <= k; ++j) {
for (int m = j; m <= k; m += j) {
dp[i][m] = (dp[i][m] + dp[i-1][j]) % MOD;
}
}
}
// 计算所有长度为 n 的序列的总数
int total = 0;
for (int j = 1; j <= k; ++j) {
total = (total + dp[n][j]) % MOD;
}
cout << total << endl;
return 0;
}
五、实现代码过程中可能遇到的问题
- 整数溢出:需要在每次加法操作后对
10^9 + 7
取模。 - 数组边界问题:要确保数组索引正确,不超过预定范围。
六、debug
- 检查初始化是否正确。
- 确保所有的模运算都已经正确地执行,以避免整数溢出。
- 验证对于所有的
m
从j
到k
是否正确地按j
的倍数递增。
正确答案:
源代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s)
#define sz(s) ((int)s.size())
#define x first
#define y second
#define ms(s,x) memset(s, x, sizeof(s))
#define all(s) s.begin(),s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;
int n, k;
void solve()
{
cin >> k >> n;
std::vector<std::vector<LL>> f(n + 1, std::vector<LL>(k + 1));
std::vector<std::vector<int>> e(k + 1);
for (int i = 1; i <= k; ++i) {
for (int j = i; j <= k; j += i) {
e[j].push_back(i);
}
}
for (int i = 1; i <= k; ++i) f[1][i] = 1;
for (int i = 2; i <= n; ++i) {
for (int j = 1; j <= k; ++j) {
for (auto v : e[j]) {
f[i][j] = (f[i][j] + f[i - 1][v]) % mod;
}
}
}
LL ans = 0;
for (int i = 1; i <= k; ++i) ans = (ans + f[n][i]) % mod;
cout << ans << '\n';
}
int main()
{
ios_base :: sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << setiosflags(ios::fixed) << setprecision(2);
int t = 1;
while (t--)
{
solve();
}
return 0;
}