标签:
大致题意:给你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