题意

​BZOJ3027​

题解

先考虑恰好吃BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数个糖果的方案。由于有BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_前缀和_02的限制,套路地想到容斥。枚举子集哪些不满足限制,然后把BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数减去所有不满足的BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_前缀和_04,剩下的就插板法就行了。假设枚举的集合中的BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数_05,答案就是:BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_分解质因数_06

然后考虑到并不是恰好BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数个,而是在BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_分解质因数_08的区间内,答案就是枚举BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数,所有的情况加起来:BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_分解质因数_10

发现可以写成一个前缀和相减的形式,答案就是BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数_11

所以只需要求BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_前缀和_12

发现这个可以BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数_13求:BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_前缀和_14

所以就做完了…吗?

还有求组合数的问题。模数是合数,不能直接lucas。可以使用分解质因数再CRT合并,但比较麻烦。有一种方法就是这样:

  • 因为有BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_前缀和_15
  • 所以有BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_分解质因数_16

这道题组合数只求BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数_17,而BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数_18范围是BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_前缀和_19,所以BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_组合数_20BZOJ 3027: [Ceoi2004]Sweet (容斥计数)_分解质因数_21范围内,直接存下来模就行了。

具体见代码

CODE

#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 2004;
const int MAXN = 2005;
LL facn = 1;
inline int C(int n, int m) {
LL re = 1;
for(int i = 1; i <= m; ++i)
re = re * (n-i+1) % (facn*mod);
return re / facn;
}
int n, m[15], sgn[(1<<10)+5];
inline int calc(int k) { return C(k+n, n); }
int main () {
int a, b, ans = 0;
scanf("%d%d%d", &n, &a, &b);
for(int i = 0; i < n; ++i) {
scanf("%d", &m[i]);
facn *= i+1;
}
sgn[0] = 1;
for(int s = 0; s < (1<<n); ++s) {
if(s&1) sgn[s] = -sgn[s>>1];
else sgn[s] = sgn[s>>1];
int t = 0;
for(int i = 0; i < n; ++i)
if(s&(1<<i)) t += m[i]+1;

int B = max(b-t, -1), A = max(a-t, 0);
if(A <= B) ans = (ans + 1ll * sgn[s] * (calc(B) - calc(A-1)) % mod) % mod;
}
printf("%d\n", (ans + mod) % mod);
}