题目:

翻译:每行输入两个数 n,kn,kn,k,输出一行一个数表示把 kkk 个 [0,n][0,n][0,n] 内的整数相加使其和为 nnn 的方案数。
输入一行两个 000 表示输入结束。
由于答案可能很大,输出方案数 mod 106\bmod 10^6mod106 的结果。
分析:
Solution1:Solution1:Solution1:记忆化搜索
1.11.11.1思路
首先大家肯定都能想到搜索,但是效率太慢,肯定会超时。
其实这是计算一个状态很多次之后导致的,所以我们开一个辅助数组 fi,jf_{i,j}fi,j 表示 iii 个数分成 jjj 个数相加有几种方法。
这种办法叫做记忆化搜索。
注意:别忘了把 fff 数组也记录上!!!
1.21.21.2代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e2+5,MOD=1e6;
int n,k;
int f[MAXN][MAXN];
int dfs(int x,int y){
if(f[x][y])return f[x][y];
if(x==0)return 1;
if(y==0)return 0;
for(int i=0;i<=x;i++)
f[x][y]+=dfs(x-i,y-1);
return f[x][y]%MOD;
}
int main(){
while(1){
scanf("%d%d",&n,&k);
if(n==k&&k==0)return 0;
printf("%d\n",dfs(n,k)%MOD);
}
return 0;
}
Soulution2:Soulution2:Soulution2:组合数学
2.02.02.0前置知识
Amn=n×(n+1)×⋯×(m−1)×mA_{m}^{n}=n\times (n+1)\times\dots\times(m-1)\times mAmn=n×(n+1)×⋯×(m−1)×m
Cmn=AmmAnn×Am−nm−nC_{m}^{n}=\dfrac{A_{m}^{m}}{A_{n}^{n}\times A_{m-n}^{m-n}}Cmn=Ann×Am−nm−nAmm
2.12.12.1思路
再次阅读题目,很容易想到插板法。
插板法顾名思义就是把 nnn 个相同的数分成 kkk 个区域。
因为数之间没有重复而且只有 n−1n-1n−1 个空隙、k−1k-1k−1 个板子,所以模板公式为 Cn−1k−1C^{k-1}_{n-1}Cn−1k−1。
但是由于可以一个区域分成 000 个数,不是我们熟知的模板,怎么办呢?
不妨考虑以下情况:
{x1+x2+⋯+xk=n0≤xi(1≤i≤k)\begin{cases}x_1+x_2+\dots+x_k=n\\0\le x_i(1\le i\le k) \end{cases}{x1+x2+⋯+xk=n0≤xi(1≤i≤k)
把 x1,x2…,xkx_1,x_2\dots,x_kx1,x2…,xk 都加上 111 。
{x1+x2+⋯+xk=n+k1≤xi(1≤i≤k)\begin{cases}x_1+x_2+\dots+x_k=n+k\\1\le x_i(1\le i\le k) \end{cases}{x1+x2+⋯+xk=n+k1≤xi(1≤i≤k)
这样就变成模板了,所以公式为 Cn+k−1k−1C^{k-1}_{n+k-1}Cn+k−1k−1。
最后用循环预处理然后用 O(1)O(1)O(1) 的时间输出即可。
2.22.22.2代码:
都讲到这里了,代码就自己写吧。
本文讲解了两种方法解决题目:记忆化搜索通过动态规划计算将k个[0, n]内的整数分组使其和为n的不同方案数;组合数学则利用插板法和组合公式C(n+k-1, k-1)简化问题。两种方法适用于不同场景,适合对算法和数学原理感兴趣的读者。

1755

被折叠的 条评论
为什么被折叠?



