本文共 1539 字,大约阅读时间需要 5 分钟。
将n划分m组,每组ai个,表示为:
如果对于每个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 ];
代码参考《挑程》
dp[i + 1][j] 定义为从前i个物品取出j个的组合数。
代码
//o(TB)#include#include 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);}
伪计数题,其实是多重背包问题