上
面
是
d
p
[
i
]
[
j
]
+
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
]
[
j
−
i
]
\color{red}上面是dp[i][j] +dp[i - 1][j] + dp[i][j - i]
上面是dp[i][j]+dp[i−1][j]+dp[i][j−i]
n个无区别物体,分为不超过m组
将n划分m组,每组ai个,表示为:
即a1 + a2 + a3 +…+ am = n;
如果对于每个i都有ai >0,那么{ai - 1} 就对应n-m 划分 m 组,
即(a1 - 1) +( a2 - 1) +( a3 - 1)+…+( am - 1) = n - m;
如果存在ai = 0, 就对应n 划分 m - 1 组。
dp[ i ][ j ] = j 个 划分 i 组
递推式为 dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[ i ][ j - i ];
代码参考《挑程》
n个物体,第i个物体有ai个(不同种类物体可以区分,相同种类物体可以区分)取出m个
dp[i + 1][j] 定义为从前i个物品取出j个的组合数。
题目链接https://blog.csdn.net/rainbowsea_1/article/details/104529566
代码
//o(TB)
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX = 1e3 + 5;
const int MAXN = 1e5 + 5;
int T, A, S, B;
int a[MAX];
int dp[MAX][MAXN];
const int MOD = 1e6;
int main() {
scanf("%d%d%d%d", &T, &A, &S, &B);
int AA;
for (int i = 0; i < A; i++) {
scanf("%d", &AA);
a[AA - 1]++;
}
long long ans = 0;
for (int i = 0; i <= T; i++) dp[i][0] = 1;
for (int i = 0 ; i < T ; i++) {
for (int j = 1; j <= B; j++) {
if(j - 1 < a[i])
dp[i + 1][j] = dp[i + 1][j - 1] + dp[i][j];
else
dp[i + 1][j] = dp[i + 1][j - 1] + dp[i][j] - dp[i][j - 1 - a[i]] + MOD; // 出现减法,要多加MOD再取模
dp[i + 1][j] %= MOD;
}
}
for (int j = S; j <= B; j++) {
ans += dp[T][j];
ans %= MOD;
}
printf("%lld\n", ans);
}
n个物体,第i个物体有ai个, 价值为mi,取出的和小于等于sum 的 种类数
伪计数题,其实是多重背包问题
链接
https://blog.csdn.net/rainbowsea_1/article/details/104529710