題目連結
非常好的題目!先想三維再想二維!
核心的想法是,如果能延伸,我們就延伸!延伸長度的話呢?枚舉他!
AC Code (3D Recursive DP)
$dp(n, k, m)$是不是只跟$dp(n - i, k - 1, min(m, n - i))$有關係呢?
核心精神是:我們嘗試去對於$dp(…, k - 1, …)$做延伸,至於延伸長度呢?就是 $n - i$!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
ll dp[55][55][55];
ll cal(int n, int k, int m)
{
if (n == 0 || k == 0 || m == 0)
return 0;
if (k > n || m > n)
return 0;
if (k == 1) {
if (n == m)
return 1;
return 0;
}
if (dp[n][k][m] != -1)
return dp[n][k][m];
ll ret = 0;
for (int i = 1; i <= m; i++) {
// add one group of bar with length i to the end of the set (n - i, k - 1,
// ...) so just make sure that i is not longer than m also, change the m
// when recursing
ret += cal(n - i, k - 1, min(m, n - i));
}
return dp[n][k][m] = ret;
}
int main()
{
int n, k, m;
while (scanf("%d %d %d", &n, &k, &m) == 3) {
memset(dp, -1, sizeof(dp));
dp[1][1][1] = 1;
printf("%lld\n", cal(n, k, m));
}
return 0;
}
|
AC Code (2D DP)
上面的那種做法你會發現 $m$ 參數其實有點多餘!
那就拿掉吧!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
int main()
{
int n, k, m;
while (scanf("%d %d %d", &n, &k, &m) == 3) {
ll dp[55][55];
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
// dp[i][j] = ans for i groups, j bars, and at most m bars per groups
// start with 1 group, 1...n bars
// 2 groups, for every bar count j, try to extent it with 1 group (j - (1 ~ m))
for (int i = 1; i <= k; i++) { // groups
for (int j = 1; j <= n; j++) { // bars
for (int x = 1; x <= m; x++) { // at most x bars
if (j - x >= 0)
dp[i][j] += dp[i - 1][j - x];
}
}
}
printf("%lld\n", dp[k][n]); // (k, n, m), m is fixed for this dp table
}
return 0;
}
|