题面
思路
首先用过题意可以很容易想到一个三重循环的解决方法:
-
代码是: #include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int a[N], f[N][N];
int main()
{
int n, m, M;
cin >> n >> m >> M;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
f[0][0] = 1;
for (int i = 1; i <= n; i ++ )
{
for (int j = 0; j <= m; j ++ )
{
for (int k = 0; k <= min(j, a[i]); k ++ )
{
f[i][j] = f[i][j] + f[i - 1][j - k];
f[i][j] %= M;
}
}
}
cout << f[n][m] << endl;
return 0;
}
意思是对于第i种物品,选j件时的方案数,可以由不选这件物品时 少用
k
k
k 件时的方案数得来 -
定义
f
i
j
f_{ij}
fij? 是前
i
i
i 种物品选
j
j
j 个的方案数 -
当
j
=
=
0
j == 0
j==0:
f
i
j
=
f
(
i
?
1
)
j
f_{ij} = f_{(i - 1)j}
fij?=f(i?1)j? -
当
1
<
=
j
<
=
k
1 <= j <= k
1<=j<=k :
-
f
i
j
=
f
(
i
?
1
)
(
j
?
0
)
+
f
(
i
?
1
)
(
j
?
1
)
+
…
+
f
(
i
?
1
)
(
j
?
j
)
f_{ij} = f{(i - 1)(j - 0)} + f{(i - 1)(j - 1)} + … + f{(i - 1)(j - j)}
fij?=f(i?1)(j?0)+f(i?1)(j?1)+…+f(i?1)(j?j) -
f
i
(
j
?
1
)
=
f
(
i
?
1
)
(
j
?
1
)
+
f
(
i
?
1
)
(
j
?
2
)
+
…
+
f
(
i
?
1
)
(
j
?
j
)
f_{i(j - 1)} = f{(i - 1)(j - 1)} + f{(i - 1)(j - 2)} + … + f{(i - 1)(j - j)}
fi(j?1)?=f(i?1)(j?1)+f(i?1)(j?2)+…+f(i?1)(j?j) -
移项得
f
i
j
=
f
(
i
?
1
)
j
+
f
i
(
j
?
1
)
f_{ij} = f_{(i - 1)j} + f_{i(j - 1)}
fij?=f(i?1)j?+fi(j?1)? -
当
k
<
j
k < j
k<j :(这里一位是多减了一个,但又因为是大于,所以顶多减成0,不会越界)
-
f
i
j
=
f
(
i
?
1
)
(
j
?
0
)
+
f
(
i
?
1
)
(
j
?
1
)
+
…
+
f
(
i
?
1
)
(
j
?
k
)
f_{ij} = f_{(i - 1)(j - 0)} + f_{(i - 1)(j - 1)} + … + f_{(i - 1)(j - k)}
fij?=f(i?1)(j?0)?+f(i?1)(j?1)?+…+f(i?1)(j?k)? -
f
i
(
j
?
1
)
=
f
(
i
?
1
)
(
j
?
1
)
+
f
(
i
?
1
)
(
j
?
2
)
+
…
+
f
(
i
?
1
)
(
j
?
k
)
+
f
(
i
?
1
)
(
j
?
k
?
1
)
f_{i(j - 1)} = f_{(i - 1)(j - 1)} + f_{(i - 1)(j - 2)} + … + f_{(i - 1)(j - k)} + f_{(i - 1)(j - k - 1)}
fi(j?1)?=f(i?1)(j?1)?+f(i?1)(j?2)?+…+f(i?1)(j?k)?+f(i?1)(j?k?1)? -
移项得
f
i
j
=
f
(
i
?
1
)
(
j
)
+
f
(
i
?
1
)
(
j
?
2
)
?
f
(
i
?
1
)
(
j
?
k
?
1
)
+
f
i
(
j
?
1
)
f_{ij} = f_{(i - 1)(j)} + f_{(i - 1)(j - 2)} - f_{(i - 1)(j - k - 1)} + f_{i(j - 1)}
fij?=f(i?1)(j)?+f(i?1)(j?2)??f(i?1)(j?k?1)?+fi(j?1)? -
最终得到两重循环的代码 #include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int a[N], f[N][N];
int main()
{
int n, m, M;
cin >> n >> m >> M;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
f[0][0] = 1;
for (int i = 1; i <= n; i ++ )
{
for (int j = 0; j <= m; j ++ )
{
if (j == 0) f[i][j] += f[i - 1][j];
else if (1 <= j && j <= a[i]) f[i][j] += (f[i - 1][j] + f[i][j - 1]);
else if (j > a[i]) f[i][j] += (f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1 - a[i]]);
f[i][j] = (f[i][j] + M) % M;
}
}
cout << f[n][m] << endl;
return 0;
}
-
注意点,在运算中包含减法,取模时,需要先加上余数再取模,不然有可能变成负数 -
参考 -
总结
当时写的时候应该是懂了没错,可是现在补题解的时候却又觉得有些一知半解,需要多多复习。
|