BZOJ4710: [Jsoi2011]分特產【組合數學+容斥】

Description

JYY 帶隊參加了若干場ACM/ICPC 比賽,帶回了許多土特產,要分給實驗室的同窗們。c++

JYY 想知道,把這些特產分給N 個同窗,一共有多少種不一樣的分法?固然,JYY 不但願任spa

何一個同窗由於沒有拿到特產而感到失落,因此每一個同窗都必須至少分得一個特產。code

例如,JYY 帶來了2 袋麻花和1 袋包子,分給A 和B 兩位同窗,那麼共有4 種不一樣的ip

分配方法:input

A:麻花,B:麻花、包子it

A:麻花、麻花,B:包子io

A:包子,B:麻花、麻花ast

A:麻花、包子,B:麻花class

Input

輸入數據第一行是同窗的數量N 和特產的數量M。方法

第二行包含M 個整數,表示每一種特產的數量。

N, M 不超過1000,每一種特產的數量不超過1000

Output

輸出一行,不一樣分配方案的總數。因爲輸出結果可能很是巨大,你只須要輸出最終結果

MOD 1,000,000,007 的數值就能夠了。

Sample Input

5 4
1 3 3 5

Sample Output

384835


思路

首先若是能夠有人不拿到就很好作

那麼就能夠考慮容斥

\(f_i\)表示有i我的分包裹而且每一個人都拿到的方案數

而後簡單容斥就能夠了


#include<bits/stdc++.h>
 
using namespace std;
 
const int N = 2010;
const int Mod = 1e9 + 7;
 
int n, m, a[N], f[N];
int fac[N], inv[N];
 
int add(int a, int b) {
  return (a += b) >= Mod ? a - Mod : a;
}
 
int sub(int a, int b) {
  return (a -= b) < 0 ? a + Mod : a;
}
 
int mul(int a, int b) {
  return 1ll * a * b % Mod;
}
 
int fast_pow(int a, int b) {
  int res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    b >>= 1;
    a = mul(a, a);
  }
  return res;
}
 
int C(int a, int b) {
  return mul(fac[a], mul(inv[a - b], inv[b]));
}
 
int main() {
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= m; i++) scanf("%d", &a[i]); 
   
  fac[0] = inv[0] = 1;
  for (int i = 1; i < N; i++) fac[i] = mul(fac[i - 1], i);
  inv[N - 1] = fast_pow(fac[N - 1], Mod - 2);
  for (int i = N - 2; i >= 1; i--) inv[i] = mul(inv[i + 1], i + 1);
   
  f[1] = 1;
  for (int i = 2; i <= n; i++) {
    int cur = 1;
    for (int j = 1; j <= m; j++) {
      cur = mul(cur, C(i + a[j] - 1, i - 1));
    }
    for (int j = 1; j < i; j++) {
      cur = sub(cur, mul(C(i, j), f[j]));
    }
    f[i] = cur;
  }
  printf("%d", f[n]);
  return 0;
}
相關文章
相關標籤/搜索