P6078 [CEOI2004] Sweets
前置芝士
这里定义 \(\dbinom{n}{k} = {n(n-1)(n-2)....(n-k+1)\over{k!}}\)。
牛顿二项式定理: \((x+y)^n = \displaystyle\sum_{k=0}^{\infty}\dbinom{n}{k}x^ky^{n-k}\)
当 \(n\) 为正数的时候, \((1+x)^n = \displaystyle\sum_{k=0}^{\infty} \dbinom{n}{k}x^k = \displaystyle\sum_{k=0}^{\infty} C_{n}^{k} x^{k}\) ,(也就是我们熟悉的二项式定理)
对于正整数 \(n\) ,我们取 \(a = -n\)
\(\dbinom{a}{k} = \dbinom{-n}{k} = {{-n(-n-1)(-n-2)...(-n-k+1)}\over{k!}} = (-1)^{k}{n(n+1)(n+2)...(n+k-1)\over k!}=(-1)^{k} \dbinom{n+k-1}{k}\)
\(\because (1+x)^{a} = \displaystyle\sum_{k=0}^{\infty} \dbinom{a}{k}x^k = \sum_{k=0}^{\infty} (-1)^{k}\dbinom {n+k-1}{k} x^k\)
\(\therefore (1+x)^{-n} = \displaystyle\sum_{k=0}^{\infty} (-1)^{k}\dbinom{n+k-1}{k} x^k\)
把 \(x\) 换成 \(-x\) 可得:
\((1-x)^{-n} = \displaystyle\sum_{k=0}^{\infty} \dbinom{n+k-1}{k} x^k = \displaystyle\sum_{k=0}^{\infty} C_{n+k-1}^{k}x^k\)
题目描述
John 得到了 \(n\) 罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第 \(i\) 个糖果罐里有 \(m_{i}\) 个糖果。John 决定吃掉一些糖果,他想吃掉至少 \(a\) 个糖果,但不超过 \(b\) 个。问题是 John 无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?
solution
生成函数入门题。
首先我们把每个糖果的生成函数写出来即: \(f(x) = x^0+x^1+x^2 ..... + x^m\).
\(\because xf(x) = x^1+x^2+....x^{m+1}\)
\(\therefore f(x)-xf(x) = 1-x^{m+1}\)
\(\therefore f(x) = {1-x^{m+1}\over{1-x}}\)
把每个糖果的生成函数乘起来: \(\displaystyle{\prod_{i=0}^{n} (1-x^{m_i+1})}\over(1-x)^n\)
分子展开之后最多有 \(2^n\) ,暴力展开即可。
分母由牛顿二项式定理可得: \((1-x)^{-n} = \displaystyle\sum_{k=0}^{\infty}C_{n+k-1}^{k}x^k\)
考虑假如说当前分子枚举到 \(x^{k}\) ,那么分母对当前答案的贡献即为 \(\displaystyle\sum_{i=a-k}^{b-k} C_{n+i-1}^{i}\) .
由 杨辉三角可得, \(\displaystyle\sum_{i=a-k}^{b-k} C_{n+i-1}^{i} = C_{n+b-k}^{b-k} - C_{n+a-k-1}^{a-k-1}\)
可以模数不是质数,没有逆元怎么办?
\(\because C_{n+b-k}^{b-k} = {(n+b-k)!\over{n!(b-k)!}}\)
\(\therefore C_{n+b-k}^{b-k} = {(n+b-k)(n+b-k-1)....(b-k+1)\over n!}\)
因为 $n! $ 很小,所以可以在算分子的时候把模数变为 \(n!\times p\) ,最后在除以 \(n!\) 即可。
注意计算 \(n!\) 的时候,一定不要模 \(p\) (好像只有我这个沙比犯了这个错误)。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int p = 2004;
int n,a,b,inv,ans,m[20];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int C(int tot)
{
if(tot < 0) return 0;
int res = 1, mod = inv * p;
for(int i = tot+1; i <= n+tot; i++) res = res * i % mod;
return (res / inv) % p;
}
void dfs(int x,int mi,int tmp)
{
if(x == n+1)
{
ans = (ans + tmp * ((C(b-mi) - C(a-mi-1)) % p) % p) % p;
return;
}
dfs(x+1,mi,tmp);
dfs(x+1,mi+m[x]+1,-tmp);
}
signed main()
{
n = read(); a = read(); b = read(); inv = 1;
for(int i = 1; i <= n; i++) m[i] = read(), inv = inv * i;
dfs(1,0,1);
printf("%lld\n",(ans+p)%p);
return 0;
}

浙公网安备 33010602011771号