题面
解法 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}\).