/*
dp[i][k] := 将整数i分成k份,分法种数
初始化:
dp[][] = { 0 }
dp[i][1] = 1
状态方程:
dp[i][k] = dp[i-1][k-1] + dp[i-k][k]
思想:(引自byvoid大神的博客:https://www.byvoid.com/blog/noip-allsolutions#.E6.95.B0.E7.9A.84.E5.88.92.E5.88.86)
每种拆分方案中,最小的数为w,按照w的不同,我们可以把拆分方案分成2类:
w=1,我们把1除去,则剩余部分正好是i-1拆分成k-1部分,一共有dp[i-1,k-1])个;
w>1,所有的数都>1,我们把所有的数-1,则正好是i-k拆分成k部分,一共有dp[i-k,k]个。
根据加法原理,得出以上方程。
答案:
dp[N][K]
*/
1 #define _CRTDBG_MAP_ALLOC
2 #include <stdlib.h>
3 #include <crtdbg.h>
4 #define _CRT_SECURE_NO_WARNINGS
5 #define HOME
6
7 #include <iostream>
8 #include <cstdlib>
9 #include <cstdio>
10 #include <cstddef>
11 #include <iterator>
12 #include <algorithm>
13 #include <string>
14 #include <locale>
15 #include <cmath>
16 #include <vector>
17 #include <cstring>
18 using namespace std;
19 const int INF = 0x3f3f3f3f;
20 const int MaxN = 210;
21 const int MaxK = 10;
22
23
24 int N, K;
25 string numStr;
26 int dp[MaxN][MaxK] = { 0 };
27
28 void Solve()
29 {
30 for (int i = 1; i <= N; ++i)
31 {
32 // 划分从2开始,因为dp[][1]已经初始化过了,否则值会被0覆盖掉。
33 for (int j = 2; j <= K; ++j)
34 {
35 if (i < j) break;
36 dp[i][j] = dp[i - 1][j - 1] + dp[i - j][j];
37 }
38 }
39 cout << dp[N][K] << endl;
40 }
41
42 int main()
43 {
44 #ifdef HOME
45 freopen("in", "r", stdin);
46 //freopen("out", "w", stdout);
47 #endif
48
49 cin >> N >> K;
50 for (int i = 1; i <= N; ++i)
51 {
52 dp[i][1] = 1;
53 }
54 Solve();
55
56 #ifdef HOME
57 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
58 _CrtDumpMemoryLeaks();
59 system("pause");
60 #endif
61 return 0;
62 }