[省选联考 2020 A 卷] 组合数问题

前言:

这是我退役赛省选中唯一一道答得令自己满意的题目。

也就是

$skyh:$难道你没$AC$

的那道题。

这道题我想了大概二十多分钟。觉得不是很简单。

然而考后出来才发现,大神们都是用数学推导$AC$的这道题。

而我,众所周知,退役在即的我菜的不行,自然不会数学推导。

所以说如果你什么也不会,你怎么做这道题呢?

于是这里有一个菜菜的组合含义理解方法。(几乎)没有任何数学推导。

(可能和luogu的某些题解撞了?不知道我没看)

虽然时间复杂度显然不优是$O(m^2log)$的但是应该比较好懂……(考场上犯傻了其实可以简单优化成$O(m^2)$)

于是打算做一个大胆的尝试:能不能给学弟(妹)们讲懂。

没关系看不懂就证明我果然还是太菜了QAQ

$Description:$

求$sumlimits_{k=0}^{n} inom{n}{k} x^k f(k)$其中$f(x)=sumlimits_{i=0}^{m} a_ix^i$

15%:$nle 10^3$

+25%:$m=0$

+20%:$x=1$

100%:$mle 10^3,others le 10^9$

(只给出了我用到的部分分)

$n le 10^3:$

你可以用多项式多点求值求出所有$f$的值然后……编不下去了。

(真庆幸没单独提出来一个$n le 5 imes 10^4$的部分分)

$m=0:$

也就是说$f(x)$是一个与$x$无关的常数。不妨设其为$1$最后乘上常数倍。

式子的形式是:$sumlimits_{k=0}^{n} x^k inom{n}{k}$

考虑实际含义:我们要对于所有$k$求出,从$n$个物品里选出$k$个,每种选法的贡献是$x^k$

于是我们可以对于这$n$个物品考虑:每个物品被选中就贡献$x$,没被选中贡献$1$,一种选法的贡献就是所有物品乘起来。

你要求出的是所有选法的贡献和,而物品之间是独立的,每种物品都会作为$1,x$出现各一次。

所以其实就是$(1+x)^n$。把这个东西展开,就是乘法分配律,就得到的是所有方案的和。

(然而写出啦我才知道,这不就是个二项式定理吗我考场上为啥要这么弱智啊)

$x=1:$

也就是说$x^k$那一项消失了。剩下的形式是$sumlimits_{k=0}^{n} f(k) inom{n}{k}$

你自然拿多项式没什么办法,所以把它展开:

$sumlimits_{i=0}^{m} a_i sumlimits_{k=0}^{n} k^i inom{n}{k}$

外边的这个$i$大力枚举。考虑内部的组合含义:

我要从$n$个物品里选出$k$个,然后贡献是$k^i$($i$是枚举的所以已知,可以视为常数)

这个$k^i$好像有点难办,怎么去理解?就是从$k$个物品里可重复地选择$i$次啊。

所以我们就是要从$n$个数里选$k$个,再在这$k$个里可重复钦定$i$次。

卡住了。于是我们改变枚举的东西:我们尝试去枚举一下这$k$个物品里有多少个物品被至少钦定过一次,设为$j$。

(因为你是可重复选择$i$次,所以枚举上届就是$i$,$i le m$复杂度没问题)

那么我们从$n$个物品里选择$j$个作为被钦定过地元素:这是$inom{n}{j}$

那么你要把$i$次选择分配给这$j$个元素,且每个元素非空。这显然是个第二类斯特林数。

(啊学弟们是不是不知道什么是斯特林数啊,那我失败了啊,我好菜啊)

然而其实只是一个$O(n^2)$递推的东西:$egin{Bmatrix} n \ k end{Bmatrix}$表示将$n$个带编号的球扔进$k$个不带标号桶里且每个桶都有球的方案数。

然而在本道题当中,根据题目含义,桶是带标号的,所以还要乘上一个阶乘。这里的阶乘和上面的组合数形成下降幂$n^{underline{j}}$

(这个东西学弟们可以当成一个dp来做)

同时你还要考虑原来$n$个里选$k$个的过程:我们知道我们所钦定的$j$个元素一定被选了,没钦定的$n-j$个元素选不选都可以,总方案数是$2^{n-j}$

所以总的方案数是$sumlimits_{i=0}^{m} a_i sumlimits_{j=0}^{i} n^{underline{j}} 2^{n-j} egin{Bmatrix} i \ j end{Bmatrix}$

两层循环暴力枚举完事。组合数的话因为$n$是确定的所以直接搞一个下降幂就好了。

无特殊限制:

$sumlimits_{k=0}^{n} inom{n}{k} x^k f(k)$

和上一个部分分一样先拆$f$得到$sumlimits_{i=0}^{m} a_i sumlimits_{k=0}^{n} k^i inom{n}{k} x^k $

和上一个部分分一样我们改变含义去枚举$j$表示被钦定的元素个数,然后接着分析:

其实除了$2^{n-j}$那部分以外,其余都和上面一样可以得到$n^{underline{j}} egin{Bmatrix} i \ j end{Bmatrix}$

然后因为$x$不再是$1$所以我们不是要计数方案,而是统计方案的贡献和。其中的贡献和第一档部分分一样,选中是$x$没选中是$1$

然后就比较简单了:你钦定的$j$个都一定被选中了是$x^j$,剩下的选不选都行,考虑所有情况就是$(x+1)^{n-j}$

最后的答案是$sumlimits_{i=0}^{m} a_i sumlimits_{j=0}^{i} egin{Bmatrix} i \ j end{Bmatrix} x^j (x+1)^{n-j} n^{underline{j}}$

我个弱智只预处理了斯特林数和下降幂,剩下的快速幂,$O(m^2log)$

然而快速幂只用到了$x^{a},(x+1)^{n-a}$。$a le m$。所以说也可以简单预处理。复杂度下降到$O(m^2)$

我相信学弟们一定没听懂。我太菜了

我就是来骗阅读量的

其实这道题这么顺下来部分分给的真棒啊……我喜欢。虽然并无卵用

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int $=1003;
 4 int st[$][$],mod,n,m,x,a[$],dpw[$],ans;
 5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 6 int main(){
 7     scanf("%d%d%d%d",&n,&x,&mod,&m); st[0][0]=1;
 8     for(int i=1;i<=m;++i)for(int j=1;j<=i;++j)st[i][j]=(1ll*st[i-1][j]*j+st[i-1][j-1])%mod;
 9     for(int i=0;i<=m;++i)scanf("%d",&a[i]);
10     for(int i=dpw[0]=1;i<=m;++i)dpw[i]=dpw[i-1]*(n-i+1ll)%mod;
11     for(int i=0;i<=m;++i)for(int j=0;j<=i;++j)ans=(ans+1ll*a[i]*st[i][j]%mod*qp(x,j)%mod*qp(x+1,n-j)%mod*dpw[j])%mod;
12     cout<<ans<<endl;
13 }
令人快活的13行AC代码
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/13325483.html