方案是多重集合,用非递增序列作代表元去掉排列重复;按末位是否为 0 得到 f(M,N)=f(M,N-1)+f(M-N,N),记忆化后 O(MN)。
OJ: roj
题目 ID: 1303
难度:普及-
标签:动态规划递推记忆化搜索数学python
创建: 2026-09-30 04:05
更新: 2026-10-05 08:34
题目描述
鸣人的查克拉能量为 1 / 7 3,输出 8。
思路
把一种方案写成非递增序列
参考代码
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
from functools import cache
@cache
def ways(m: int, n: int) -> int:
"""把 m 点查克拉分配给 n 个有序影分身(允许为 0)的方案数。
只看每个分身的点数构成的非递增序列:序列最大值为 0 时全 0 只有一种;
只用 1 个分身时方案唯一。第一个分身取 0 点 → ways(m, n-1);
每个分身都至少 1 点 → 全体减 1,对应 ways(m-n, n)。
"""
if m == 0 or n == 1:
return 1
if m < n:
return ways(m, m) # 多出的分身只能拿 0 点,等价于没有它们
return ways(m, n - 1) + ways(m - n, n)
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
out: list[str] = []
T = next(data)
for _ in range(T):
m, n = next(data), next(data)
out.append(str(ways(m, n)))
print('\n'.join(out))
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 08:33
* update_at: 2026-10-05 08:34
*/
#include <cstdio>
typedef long long ll;
const int MAXM = 15;
const int MAXN = 15;
ll memo[MAXM][MAXN]; // memo[m][n] = 把 m 点查克拉分给 n 个影分身(允许为 0)的方案数
bool vis[MAXM][MAXN]; // vis[m][n] 标记 memo[m][n] 是否已经求出
// f(m, n):只看每个分身的点数构成的非递增序列,n=1 或 m=0 时方案唯一。
ll f(ll m, ll n) {
if (m == 0 || n == 1) {
return 1;
}
if (m < n) {
return f(m, m); // 多出的分身只能拿 0 点,等价于没有它们
}
if (vis[m][n]) {
return memo[m][n];
}
vis[m][n] = true;
// 末位 a_n 为 0 -> f(m, n-1);每个分身都至少 1 点 -> 全体减 1 -> f(m-n, n)
memo[m][n] = f(m, n - 1) + f(m - n, n);
return memo[m][n];
}
int main() {
ll t;
scanf("%lld", &t);
for (ll i = 1; i <= t; i++) {
ll m, n;
scanf("%lld %lld", &m, &n);
printf("%lld\n", f(m, n));
}
return 0;
}