CF414B Mashmokh and ACM 题解
题意概述
给定 \(n,k \ (1\le n,k\le 2000)\) ,求使用 \(1,2,...,n\) 可以构造的长度为 \(k\) 的子序列个数(允许重复)。其中子序列 \(1 \le b_1,b_2,\dots,b_k \le n\) 满足 \(b_{i-1}|b_i\ (\ 2\le i\le n)\) 。
思路
最长子序列数量的变形问题,固定子序列长度。于是定义 \(f[i][k]\) 表示以 \(i\) 结尾长度为 \(k\) 的子序列个数,不难发现
\[f[i][k]=\sum_{j|i}f[j][k-1]
\]
- \(j=1,2,...,n\);
- \(f[i][1]=1, \ i\in[1,n]\)。
三重循环暴力枚举实现该 DP 的时间复杂度为 \(O(n^2k)\),根据题目数据,当 \(n=k=2000\) 时,循环次数高达 \(8 \times 10^9\),无法满足题目要求。
优化 1
不难发现,若 \(j|i\),则 \(\exists t\),使得 \(j\cdot t = i\),那么有 \(1\le \min(j,t)\le \sqrt{i}\),这表明只需枚举到 \(\sqrt{i}\) 即可。特别地,若 \(j=\sqrt{i}\),需特判。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1'000'000'007;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int n, k;
cin >> n >> k;
vector f(n + 1, vector<int>(k + 1));
for (int i = 1; i <= n; i ++) f[i][1] = 1;
for (int u = 2; u <= k; u ++) {
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= i / j; j ++) {
if (i % j == 0) {
f[i][u] = (f[i][u] + f[j][u - 1]) % MOD;
if (j != i / j) {
f[i][u] = (f[i][u] + f[i / j][u - 1]) % MOD;
}
}
}
}
}
int ans = 0;
for (int i = 1; i <= n; i ++) {
ans = (ans + f[i][k]) % MOD;
}
cout << ans;
return 0;
}
复杂度分析
上述代码的三层循环次数可写作
\[k \sum_{i=1}^{n}\sqrt{i}
\]
而当 \(n\to \infty\) 时,内存循环
\[\sum_{i=1}^{n}\sqrt{i}\approx \int_{1}^{n}\sqrt{x}\,dx=\frac{2}{3}x^{3/2}\Big|_{1}^{n}=\frac{2}{3}(n^{3/2}-1)
\]
故时间复杂度为
\[O(k\cdot n^{3/2})
\]
优化 2
换一种思考方式,不妨对每个 \(j\) 取枚举它的倍数 \(i\)。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1'000'000'007;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int n, k;
cin >> n >> k;
vector f(n + 1, vector<int>(k + 1));
for (int i = 1; i <= n; i ++) f[i][1] = 1;
for (int u = 2; u <= k; u ++) {
for (int j = 1; j <= n; ++ j) {
for (int i = j; i <= n; i += j) {
f[i][u] = (f[i][u] + f[j][u - 1]) % MOD;
}
}
}
long long ans = 0;
for (int i = 1; i <= n; ++ i) {
ans = (ans + f[i][k]) % MOD;
}
cout << ans;
return 0;
}
复杂度分析
上述代码的循环次数可被写作
\[k\cdot \sum_{j=1}^{n} \Big\lfloor\frac{n}{j}\Big\rfloor
\]
当 \(n\to \infty\) 时
\[\sum_{j=1}^{n}\Big\lfloor\frac{n}{j}\Big\rfloor\approx n\sum_{j=1}^n \frac{1}{j}=nH_n
\]
其中调和级数
\[H_n= \Theta(\log n)
\]
故时间复杂度为
\[O(k n\log n)
\]

浙公网安备 33010602011771号