BZOJ5215: [Lydsy2017省队十连测]商店购物
? 解题记录 ? ? BZOJ ? ? 动态规划 ? ? 组合数 ?    2018-09-25 08:00:44    585    0    0

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

Sample Output

6
HINT
6 种方案分别为:{0; 0; 8}; {1; 0; 7}; {2; 0; 6}; {0; 1; 7};
{1; 1; 6}; {2; 1; 5}。

HINT

 

Source

Claris原创,本站版权所有

前半部分是一个很简单的dp前缀和优化,后半部分就是一个组合数选板法。组合数可以以看网上一篇很好的博客:很好的博客

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define LL long long
  4. #define For(i, a, b) for(register int i = a; i <= b; ++i)
  5. #define Down(i, a, b) for(register int i = a; i >= b; --i)
  6. using namespace std;
  7. const int M = 305;
  8. const int N = 5e6 + 5;
  9. const int mod = 1e9 + 7;
  10. int w[M], dp[M][M * M], sum[M][M * M];
  11. int n, m, k;
  12. LL inv[N << 1], step[N << 1];
  13.  
  14. LL fpow(LL a, int b) {
  15. LL ans = 1;
  16. while(b) {
  17. if(b & 1) ans = ans * a % mod;
  18. a = a * a % mod; b >>= 1;
  19. }
  20. return ans;
  21. }
  22.  
  23. void pre(int n) {
  24. inv[0] = step[0] = 1;
  25. For(i, 1, n) step[i] = step[i - 1] * i % mod;
  26. inv[n] = fpow(step[n], mod - 2);
  27. Down(i, n - 1, 1)
  28. inv[i] = inv[i + 1] * (i + 1) % mod;
  29. }
  30.  
  31. LL C(int n, int m) {
  32. return (step[n] * inv[n - m] % mod) * inv[m] % mod;
  33. }
  34.  
  35. int main() {
  36. //freopen("shopping.in", "r", stdin);
  37. //freopen("shopping.out", "w", stdout);
  38. scanf("%d%d%d", &n, &m, &k);
  39. for(register int i = 1; i <= m; ++i)
  40. scanf("%d", &w[i]);
  41. pre(10000000), dp[0][0] = 1, sum[0][0] = 1;
  42. int tmp, mxt = 300 * 300;
  43. for(register int j = 1; j <= mxt; ++j)
  44. sum[0][j] = (sum[0][j - 1] + dp[0][j]) % mod;
  45. for(register int i = 1; i <= m; ++i) {
  46. for(register int j = mxt; j >= 0; --j) {
  47. tmp = max(j - w[i] - 1, -1);
  48. tmp = tmp == -1 ? 0 : sum[i - 1][tmp];
  49. dp[i][j] += (sum[i - 1][j] - tmp) % mod;
  50. dp[i][j] %= mod;
  51. }
  52. sum[i][0] = dp[i][0];
  53. for(register int j = 1; j <= mxt; ++j)
  54. sum[i][j] = (sum[i][j - 1] + dp[i][j]) % mod;
  55. }
  56. int left = 0, ans = 0;
  57. if(n == m) return printf("%d", (dp[m][k] + mod) % mod), 0;
  58. for(register int i = 0; i <= mxt; ++i) {
  59. left = k - i;
  60. ans += dp[m][i] * C(left + n - m - 1, n - m - 1) % mod;
  61. ans %= mod;
  62. }
  63. printf("%d", (ans + mod) % mod);
  64. return 0;
  65. }


上一篇: BZOJ5216: [Lydsy2017省队十连测]公路建设

下一篇: BZOJ5217: [Lydsy2017省队十连测]航海舰队

585 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航