很明显, 这是一道组合题
乍一看,是隔板,好像又不是
隔板怎么可以是小于等于呢——当然可以
例子:
x
1
+
x
2
+
x
3
≤
n
x_1+x_2+x_3\le n
x1+x2+x3≤n
我们可以发现
n
−
x
1
−
x
2
−
x
3
≥
0
n-x_1-x_2-x_3\ge 0
n−x1−x2−x3≥0
所以一定存在一个正整数
x
4
x_4
x4使得
x
1
+
x
2
+
x
3
+
x
4
=
n
x_1+x_2+x_3+x_4=n
x1+x2+x3+x4=n
小于等于问题解决了
然后是
0
≤
x
i
≤
c
i
0\le x_i\le c_i
0≤xi≤ci
其实就是容斥原理,不过因为
x
i
x_i
xi可以为零,所以减去
c
i
c_i
ci的同时还要多减去一
最麻烦的在于它的模数2004
不是质数,时限又是100ms
所以,我们要在算组合数的时候速战速决,又不能用逆元
于是,一种全新的方法出现了——在取模的同时又要保证是分母的倍数,于是可以预处理出分母,计算时取
2004
×
2004\times
2004×分母的模
题目结束了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2007, md = 1e9 + 7;
int n, c[N], a, b;
int C(int a, int b)
{
if (a < b)
return 0;
int ans = 1, c = 1;
for (int i = 1, j = a; i <= b; i++, j--)
c *= i;
for (int i = 1, j = a; i <= b; i++, j--)
ans = ans * j % (2004 * c);
return ans / c;
}
int solve(int a, int b, int x)
{
// cout << x << endl;
if (a > n)
return b * C(x + n, n) % 2004;
return (solve(a + 1, b, x) + solve(a + 1, -b, x - c[a] - 1)) % 2004;
}
signed main()
{
scanf("%lld%lld%lld", &n, &a, &b);
for (int i = 1; i <= n; i++)
scanf("%lld", c + i);
printf("%lld", ((solve(1, 1, b) - solve(1, 1, a - 1)) % 2004 + 2004) % 2004);
}
// 2026*3=6078