题面
解法 1
设 \(n\) 的划分数为 \(f(n)\) , 则
\[f(n)=
\begin{cases}
1 & n=1\\
f(n-1) & n\equiv 1\pmod{2}, n\ne 1 \\
f(n-1)+f(\lfloor n/2\rfloor) & n\equiv 0\pmod{2}
\end{cases}\]
证明略. 时间复杂度 \(O(n)\), 空间复杂度 \(O(n)\). 测评时耗时 \(3.502647\ \text{ms}\), 占用 \(3952\ \text{KiB}\).
程序
#include <iostream> #include <cstring> using namespace std; #define MAXN 1000050 #define MOD 1000000007 int d[MAXN]; void calcdp(int m) { d[1] = 1; for (int i = 2; i <= m; i++) if (i % 2) d[i] = d[i - 1]; else d[i] = (d[i - 1] + d[i / 2]) % MOD; } int main() { int m; cin >> m; calcdp(m); cout << d[m] << endl; return 0; }
解法 2
考虑枚举法. 为了保证正确性(不重), 可以采用加入单调性的方法.
设 \(n\) 的划分中最小的不小于 \(2^i\) 的划分数为 \(f(n,i)\) , 则
\[
f(n, i)=
\begin{cases}
\sum_{2^j< n}f(n-2^j,j)&n>1\\
1&n=1
\end{cases}
\]
时间复杂度为 \(O(n\log^2n)\) , 空间复杂度 \(O(n\log{n})\). 可保证40分. \(n=10^6\) 时耗时约 \(3\ \text{s}\).
观察题目所给样例, \(7\) 的划分中没有以 \(2\) 及以上开头的. 这是因为 \(2\nmid 7\). 于是可以有
\[
f(n, i)=
\begin{cases}
0&2^i\nmid n\\
\sum_{2^j< n}f(n-2^j,j)&n>1\\
f(n, i)=1&n=1
\end{cases}
\]
从上至下呈覆盖关系.
程序
#include <iostream> #include <cstring> using namespace std; #define MAXN 1000050 #define LG_MAXN 24 #define MOD 1000000007 int d[MAXN][LG_MAXN]; int dp(int m, int n) { if (d[m][n] > -1) return d[m][n]; if (m % (1 << n)) return d[m][n] = 0; // (*) if (m <= 1) return d[m][n] = 1; int ans = 0; for (int i = n; (1 << i) <= m; i++) { ans += dp(m - (1 << i), i); ans %= MOD; } return d[m][n] = ans; } void calcdp(int m) { memset(d, -1, sizeof(d)); for (int i = 1; i <= m; i += 1000) dp(i, 0); dp(m, 0); } int main() { int m; cin >> m; calcdp(m); cout << d[m][0] << endl; return 0; }
为了避免栈溢出, 可以采用分段计算的方法. 测评时耗时 \(312.835601\ \text{ms}\), 占用 \(93860\ \text{KiB}\).