[BZOJ3028]食物(生成函数+讲解)

题目:

我是超链接

题解:

关于生成函数讲的最好的就是。。百度一下
生成函数,对于一个数列来讲就是一个函数,ta本身的x没有任何意义,而系数则是数列中的每一个数字,如果数列为h0,h1,h2..hn的话,生成函数g(x)就是
g(x)=infi=0hixi g ( x ) = ∑ i = 0 i n f h i x i

这道题目是当做例题的裸题
应对这种一看就炒鸡麻烦但确实是排列组合的题目,这里的次方数可以表示选择了几个,可以发现数字幂相乘=以这个数字为底,次方数相加。那么只要我们把所有这些的生成函数列出来,化简,相乘,得到的x^n的系数就是答案

那么上面是套路,下面我针对这道题目来说一下
第一步列出来,这里的数列表示的是【方案数】,或者说是【有没有这种选法】
那么我们可以得到这样的柿子
(1+x2+x4+...)(1+x)(1+x+x2)(x+x3+x5+...)(1+x4+x8+...)(1+x+x2+x3)(1+x)(1+x3+x6+...) ( 1 + x 2 + x 4 + . . . ) ( 1 + x ) ( 1 + x + x 2 ) ( x + x 3 + x 5 + . . . ) ( 1 + x 4 + x 8 + . . . ) ( 1 + x + x 2 + x 3 ) ( 1 + x ) ( 1 + x 3 + x 6 + . . . )

第二步化简:我们对于每个柿子单独化简
(1+x2+x4+...) ( 1 + x 2 + x 4 + . . . ) 这东西一看就是等比数列啊,公比 q=x2 q = x 2 ,分子因为n的范围是inf,所以直接省略,那么原式= 11x2 1 1 − x 2
(x2+x+1)=1x31x ( x 2 + x + 1 ) = 1 − x 3 1 − x
(x+x3+x5+...)=x1x2 ( x + x 3 + x 5 + . . . ) = x 1 − x 2
(1+x4+x8+...)=11x4 ( 1 + x 4 + x 8 + . . . ) = 1 1 − x 4
(1+x+x2+x3)=1x41x=(1+x)(1+x2) ( 1 + x + x 2 + x 3 ) = 1 − x 4 1 − x = ( 1 + x ) ( 1 + x 2 )
(1+x3+x6+...)=11x3 ( 1 + x 3 + x 6 + . . . ) = 1 1 − x 3

第三步相乘,我们把第一步化简后的柿子乘起来
最后得到的柿子 x(1x)4 x ( 1 − x ) 4
这玩意还是没法做啊
那么我们隆重推出的就是化简目前状态的通法:二项式定理

(a+b)n=r=0nC(n,r)anrbr ( a + b ) n = ∑ r = 0 n C ( n , r ) a n − r b r

结论就是 (x+1)n=infi=0C(n,i)xi ( x + 1 ) n = ∑ i = 0 i n f C ( n , i ) x i n对于负数/实数一样是成立的
怎么推的?看看上面那个再看看下面这个就看出来了吧

上面那个结论的伸展(此时系数是-k)

n=0infC(n+k1,k1)xn=1(1x)k ∑ n = 0 i n f C ( n + k − 1 , k − 1 ) x n = 1 ( 1 − x ) k

这个东西的意义是什么?有一种很有名的排列组合方法——–插板法
n个相同的小球放到m个不同的盒子里。
- 不允许出现空盒子?
- 设想有n个小球排成一排,要往中间的n-1个空档里插入m-1个板子把它们分成m份
在同一份里的小球就放在一个盒子里,方案数就是C(n-1,m-1)
- 允许出现空盒子?
- 每个盒子里先放一个“虚”球,方案数是C(n+m-1,m-1)

那么我们也就可以继续画柿子了

x(1x)4=xn=0infC(n+41,41)xn=xn=0infC(n+3,3)xn=n=0infC(n+3,3)xn+1 x ( 1 − x ) 4 = x ∑ n = 0 i n f C ( n + 4 − 1 , 4 − 1 ) x n = x ∑ n = 0 i n f C ( n + 3 , 3 ) x n = ∑ n = 0 i n f C ( n + 3 , 3 ) x n + 1

那么我们要想知道x^n的系数,答案就是 C(n+2,3)=n(n+1)(n+2)6 C ( n + 2 , 3 ) = n ( n + 1 ) ( n + 2 ) 6
完结撒花,画的他妈妈都不认识啦

代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define mod 10007
#define inv6 1668
int read()
{
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=(x*10+ch-'0')%mod,ch=getchar();
    return x;
}
int main()
{
    int n;n=read();
    printf("%d\n",n*(n+1)%mod*(n+2)%mod*inv6%mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值