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\)

题目描述

luogu

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;
}
posted @ 2021-01-07 16:22  genshy  阅读(96)  评论(0)    收藏  举报