标签:
大致题意:给你a个数字,这些数字范围是1到t,每种数字最多100个,求问你这些a个数字进行组合(不包含重复),长度为s到b的集合一共有多少个。
思路:d[i][j]——前i种数字组成长度为j的集合有多少个。
那么,当前考虑第i种数字,我要组成长度为j的集合,只用在前i-1种数字所组成的集合中,只要添加0...cnt[i]个第i种数字之后长度能够达到j的那些集合数加起来
所以方程可以写成d[i][j] = ∑(cnt[i],0) d[i-1][j-k]。
每种数字最多100个,数字最大为1000,那么长度最大为100*1000(10W),那么所开辟的数组可能不够。
从方程可以看到,当前数组计算只会用到相邻行的数组元素,所以可以采用滚动数组。
AC代码:
#include <cstdio> #include <cstring> using namespace std; const int N = 1005; const int N2 = 100005; const int MOD = 1000000; int t,s,a,b,d[2][N2]; int cnt[N]; void solve() { memset(d, 0, sizeof(d)); int total = 0; d[0][0] = 1; for(int i = 1; i <= t; i++) { total += cnt[i]; for(int k = 0; k <= cnt[i]; k++) { for(int j = k; j <= total; j++) { d[1][j] = (d[1][j]+d[0][j-k])%MOD; } } for(int j = 0; j <= total; j++) d[0][j] = d[1][j],d[1][j] = 0; } int ans = 0; for(int i = s; i <= b; i++) ans = (ans+d[0][i])%MOD; printf("%d\n", ans); } int main() { while(~scanf("%d %d %d %d", &t, &a, &s, &b)) { memset(cnt, 0, sizeof(cnt)); for(int i = 0; i < a; i++) { int x; scanf("%d", &x); cnt[x]++; } solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/sevenun/p/5453454.html