计数类的问题,要求不重复,把每种物品单独考虑。
将和号递推可以把转移优化O(1)。
f[i = 第i种物品][j = 总数量为j] = 方案数
f[i][j] = sigma{f[i-1][j-k],(k = [0,min(j,c[i])])}
把和号展开
f[i][j] : j-0,j-1,...,j-a[i]
f[i][j-1] : j-1,j-2,...,j-a[i]-1
中间部分是一样的可以避免重复计算。
#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> //#include<bits/stdc++.h> using namespace std; int T, A, S, B; const int maxt = 1e3+5, maxa = 1e5+5, mod = 1e6; int f[2][maxa]; int c[maxt]; //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif scanf("%d%d%d%d",&T,&A,&S,&B); for(int i = A; i--;){ int x; scanf("%d",&x); c[x]++; } f[0][0] = f[1][0] = 1; //不选方案数为1 for(int i = 1; i <= T; i++){ int a = i&1, b = a^1; for(int j = 1; j <= B; j++){ if(j-c[i]>0){ f[a][j] = ( f[a][j-1] + f[b][j] - f[b][j-1-c[i]] ) % mod; }else { f[a][j] = ( f[a][j-1] + f[b][j] ) % mod; } } } int sum = 0, *F = f[T&1]; for(int i = S; i <= B; i++){ sum = (sum + F[i]) % mod; } printf("%d ",sum<0?sum+mod:sum); return 0; }