Description
在 Byteland一共开着 n家商店,编号依次为 1到 n,其中编号为1到 m的商店有日消费量上限,第 i家商店的日消
费量上限为wi。Byteasar每次购物的过程是这样的:依次经过每家商店,然后购买非负整数价格的商品,并在结账
的时候在账本上写上在这家商店消费了多少钱。当然,他在这家商店也可以什么都不买,然后在账本上写上一个0
。这一天, Byteasar日常完成了一次购物,但是他不慎遗失了他的账本。他只记得自己这一天一共消费了多少钱
,请写一个程序,帮助 Byteasar计算有多少种可能的账单。
Input
第一行包含三个正整数
n, m, k,分别表示商店的个数、有限制的商店个数以及总消费量。
第二行包含 m个整数,依次表示 w1;w2...wm。
1 ≤ m ≤ n,0≤ wi ≤ 300,1 ≤ n, k ≤ 5000000
m<=300
Output
输出一行一个整数,即可能的账单数,由于答案可能很大,请对1000000007取模输出。
Sample Input
3 2 8
2 1
2 1
Sample Output
6
HINT
6 种方案分别为:{0; 0; 8}; {1; 0; 7}; {2; 0; 6}; {0; 1; 7};
{1; 1; 6}; {2; 1; 5}。
HINT
6 种方案分别为:{0; 0; 8}; {1; 0; 7}; {2; 0; 6}; {0; 1; 7};
{1; 1; 6}; {2; 1; 5}。
HINT
Source
前半部分是一个很简单的dp前缀和优化,后半部分就是一个组合数选板法。组合数可以以看网上一篇很好的博客:很好的博客
#include<cstdio> #include<algorithm> #define LL long long #define For(i, a, b) for(register int i = a; i <= b; ++i) #define Down(i, a, b) for(register int i = a; i >= b; --i) using namespace std; const int M = 305; const int N = 5e6 + 5; const int mod = 1e9 + 7; int w[M], dp[M][M * M], sum[M][M * M]; int n, m, k; LL inv[N << 1], step[N << 1]; LL fpow(LL a, int b) { LL ans = 1; while(b) { if(b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } void pre(int n) { inv[0] = step[0] = 1; For(i, 1, n) step[i] = step[i - 1] * i % mod; inv[n] = fpow(step[n], mod - 2); Down(i, n - 1, 1) inv[i] = inv[i + 1] * (i + 1) % mod; } LL C(int n, int m) { return (step[n] * inv[n - m] % mod) * inv[m] % mod; } int main() { //freopen("shopping.in", "r", stdin); //freopen("shopping.out", "w", stdout); scanf("%d%d%d", &n, &m, &k); for(register int i = 1; i <= m; ++i) scanf("%d", &w[i]); pre(10000000), dp[0][0] = 1, sum[0][0] = 1; int tmp, mxt = 300 * 300; for(register int j = 1; j <= mxt; ++j) sum[0][j] = (sum[0][j - 1] + dp[0][j]) % mod; for(register int i = 1; i <= m; ++i) { for(register int j = mxt; j >= 0; --j) { tmp = max(j - w[i] - 1, -1); tmp = tmp == -1 ? 0 : sum[i - 1][tmp]; dp[i][j] += (sum[i - 1][j] - tmp) % mod; dp[i][j] %= mod; } sum[i][0] = dp[i][0]; for(register int j = 1; j <= mxt; ++j) sum[i][j] = (sum[i][j - 1] + dp[i][j]) % mod; } int left = 0, ans = 0; if(n == m) return printf("%d", (dp[m][k] + mod) % mod), 0; for(register int i = 0; i <= mxt; ++i) { left = k - i; ans += dp[m][i] * C(left + n - m - 1, n - m - 1) % mod; ans %= mod; } printf("%d", (ans + mod) % mod); return 0; }
没有帐号? 立即注册