[CEOI 2004]Sweet

Posted NaVi_Awson

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CEOI 2004]Sweet相关的知识,希望对你有一定的参考价值。

Description

题面链接

\\(n\\) 种糖果。第 \\(i\\) 种糖果有 \\(m_i\\) 个。取出一些糖果,至少 \\(a\\) 个,但不超过 \\(b\\) 个。求方案数。

\\(1\\leq n\\leq 10 , 0\\leq a\\leq b\\leq 10000000 , 0\\leq m_i\\leq 1000000\\)

Solution

先考虑没有下界和上界的情况。

对于第 \\(i\\) 种糖果,我们写出形式幂级数 \\(\\sum\\limits_{j=0}^{m_i}x^j\\)

那么式子 \\(\\prod\\limits_{i=1}^n\\sum\\limits_{j=0}^{m_i}x^j\\) 中系数和就是答案。

由于 \\(\\sum\\limits_{i=0}^nx^i\\cdot(1-x)=1-x^{n+1}\\) ,故原式可化为 \\(\\prod\\limits_{i=1}^n\\frac{1-x^{m_i+1}}{1-x}=\\frac{\\prod\\limits_{i=1}^n1-x^{m_i+1}}{(1-x)^n}\\)

由生成函数的公式,原式可化为 \\(\\left(\\prod\\limits_{i=1}^n1-x^{m_i+1}\\right)\\cdot\\left(\\sum\\limits_{i=0}^{\\infty}C_{i+n-1}^{n-1}x^i\\right)\\)

现在设 \\(f_i\\) 表示最多选 \\(i\\) 个糖的方案数。 \\(f_i\\) 就是上述式子中的 \\([0,i]\\) 次项式的系数和。

由于 \\(n\\) 比较小,我们可以将前一部分的式子暴力拆解。用 \\(2^n\\) 的深搜实现。

对于搜出来的某一个次数 \\(p\\) ,那么对于 \\(f_i\\) ,后面部分有贡献的只有 \\(\\sum\\limits_{j=0}^{i-p}C_{j+n-1}^{n-1}x^j\\) 。由于 \\(C_n^n=1,C_n^{n-1}+C_n^n=C_{n+1}^n\\) 得后一部分的式子可以直接化简为 \\(C_{i+n-p}^{n}\\)

则原题就是求 \\(f_b-f_{a-1}\\)

Code

//It is made by Awson on 2018.2.16
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar(\'\\n\'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int MOD = 2004;
void read(int &x) {
    char ch; bool flag = 0;
    for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == \'-\')) || 1); ch = getchar());
    for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    x *= 1-2*flag;
}
void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(int x) {if (x < 0) putchar(\'-\'); print(Abs(x)); }

int n, a, b, m[15], ans, I;

int C(int n, int m) {
    if (n < m) return 0;
    LL x = 1;
    for (int i = 1; i <= m; i++) x *= i;
    LL mod = x*MOD, ans = 1;
    for (int i = n-m+1; i <= n; i++) ans = ans*i%mod;
    return int(ans/x)%MOD;
}
void dfs(int cen, int cnt, int sum) {
    if (cen > n) {
        if (cnt&1) ans -= C(I+n-sum, n);
        else ans += C(I+n-sum, n);
        return;
    }
    dfs(cen+1, cnt, sum);
    dfs(cen+1, cnt+1, sum+m[cen]);
}
int f(int x) {
    if (x < 0) return 0; I = x;
    ans = 0; dfs(1, 0, 0);
    return ans%MOD;
}
void work() {
    read(n); read(a); read(b);
    for (int i = 1; i <= n; i++) read(m[i]), ++m[i];
    writeln(((f(b)-f(a-1))%MOD+MOD)%MOD);
}
int main() {
    work(); return 0;
}

以上是关于[CEOI 2004]Sweet的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3027: [Ceoi2004]Sweet (生成函数)

bzoj 3027: [Ceoi2004]Sweet生成函数+组合数学

[CEOI2004]锯木厂选址

CEOI 2004 Trial session Problem. Journey DFS

动态规划(斜率优化):[CEOI2004]锯木厂选址

[Ceoi2004]Journey