设 f(i) 为 i 能生成的数的个数,由 f(i)=1+Σf(x) 差分得 f(i)=f(i-1)+[i 偶]·f(i/2),顺序递推求 f(n)。
OJ: roj
题目 ID: 1316
难度:普及-
标签:递推动态规划计数python
创建: 2026-09-30 04:54
更新: 2026-10-05 09:11
题目描述
输入自然数 6,输出 6,对应
思路
设
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 04:54
# update_at: 2026-09-30 04:54
import sys
def count_forms(n: int) -> int:
"""返回自然数 n 按规则能生成的所有数的个数(含 n 本身)。
记 f(i) 为 i 能生成的数的个数:i 本身算一个,再加上「左边补一个不超过 i/2 的
数 x」得到的全部数,每个 x 贡献 f(x) 个,故 f(i) = 1 + sum(f(1..i//2))。
与前一式作差:i 为奇数时 i//2 == (i-1)//2,不新增可用的前半段;
i 为偶数时多出一项 f(i//2),于是 f(i) = f(i-1) + (i 为偶数 ? f(i//2) : 0)。
"""
f = [1] * (n + 1) # f[0] = f[1] = 1:0 和 1 都只能算自身
for i in range(2, n + 1):
f[i] = f[i - 1] + (f[i // 2] if i % 2 == 0 else 0)
return f[n]
def solve() -> None:
n = next(iter(map(int, sys.stdin.buffer.read().split())))
print(count_forms(n))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 09:11
* update_at: 2026-10-05 09:11
*/
#include <iostream>
using namespace std;
typedef long long ll;
const int MAXN = 1005; // n <= 1000,多开几个防止越界
ll f[MAXN]; // f[i]:从 i 出发能生成的不同数的个数(含 i 本身)
int main() {
ll n;
cin >> n;
// f[0] = f[1] = 1:0 和 1 左边都补不了正整数,只能算自己
f[0] = 1;
f[1] = 1;
// 差分后的递推:奇数不变,偶数多出 f[i/2]
for (ll i = 2; i <= n; i++) {
if (i % 2 == 0) {
f[i] = f[i - 1] + f[i / 2];
} else {
f[i] = f[i - 1];
}
}
cout << f[n] << endl;
return 0;
}