Aizu 2595(容斥原理)

题目意思:

计算 x1 + x2 + .. xD =N (xi<X) (X,N<=2000, D<1e12 )

分析:

我们有这样的一个思路,求d[i][j]代表用i个空位放置j个每个都非空,且为合法放置的个数,那么res = sum( d[i ][ n ] *C(D , i));

那么我们来分析一下容斥的思路。

容斥首先确定,性质,和结果怎样用性质表示。

定义 , Ai 为第i天放置的元素小于X, 那么ans = 所有D个集合的交集。

这样就可用容斥了, 但要注意的是每一步求 k 个集合有>=x个元素,其他D-k个集合有>=0个元素,那么这个问题,可以等价转换为每个集合放置>=0个元素,放置元素总个数为

N - k * X;

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 2000 + 10, MOD = 1e9 + 7;
int inv[MAXN];

LL pm(LL a, LL n) {
  LL r = 1;
  for (; n; n >>= 1) {
    if (n & 1) r = r * a % MOD;
    a = a * a % MOD;
  }
  return r;
}

LL C(LL n, int m) {
  if (m < 0 || n < 0 || n < m) return 0;
  LL r = 1;
  for (int i = 1; i <= m; ++ i) {
    r = (n - i + 1) % MOD * r % MOD * inv[i] % MOD;
  }
  return r;
}

int main() {
  for (int i = 1; i < MAXN; ++ i) inv[i] = pm(i, MOD - 2);
  LL N, D, X , res = 0;
  while(scanf("%lld%lld%lld",&N,&D,&X)==3 && N){
   res = 0;
   for(int i=0; i*X<=N && i <= D; i++){
       LL xi = C(D,i);
       LL com = C(D-1+N-i*X , N-i*X);
       LL flag = (i&1) ? -1 : 1;
       res = (res + flag*xi*com%MOD + MOD)%MOD;
   }
   printf("%d\n",(int)res);
  }
  return 0;
}


你可能感兴趣的:(Aizu 2595(容斥原理))