题目意思:
计算 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;
}