[省选联考 2020 A 卷] 组合数问题
前言:
这是我退役赛省选中唯一一道答得令自己满意的题目。
也就是
$skyh:$难道你没$AC$
的那道题。
这道题我想了大概二十多分钟。觉得不是很简单。
然而考后出来才发现,大神们都是用数学推导$AC$的这道题。
而我,众所周知,退役在即的我菜的不行,自然不会数学推导。
所以说如果你什么也不会,你怎么做这道题呢?
于是这里有一个菜菜的组合含义理解方法。(几乎)没有任何数学推导。
(可能和luogu的某些题解撞了?不知道我没看)
虽然时间复杂度显然不优是$O(m^2log)$的但是应该比较好懂……(考场上犯傻了其实可以简单优化成$O(m^2)$)
于是打算做一个大胆的尝试:能不能给学弟(妹)们讲懂。
没关系看不懂就证明我果然还是太菜了QAQ
$Description:$
求$\sum\limits_{k=0}^{n} \binom{n}{k} x^k f(k)$其中$f(x)=\sum\limits_{i=0}^{m} a_ix^i$
15%:$n\le 10^3$
+25%:$m=0$
+20%:$x=1$
100%:$m\le 10^3,others \le 10^9$
(只给出了我用到的部分分)
$n \le 10^3:$
你可以用多项式多点求值求出所有$f$的值然后……编不下去了。
(真庆幸没单独提出来一个$n \le 5 \times 10^4$的部分分)
$m=0:$
也就是说$f(x)$是一个与$x$无关的常数。不妨设其为$1$最后乘上常数倍。
式子的形式是:$\sum\limits_{k=0}^{n} x^k \binom{n}{k}$
考虑实际含义:我们要对于所有$k$求出,从$n$个物品里选出$k$个,每种选法的贡献是$x^k$
于是我们可以对于这$n$个物品考虑:每个物品被选中就贡献$x$,没被选中贡献$1$,一种选法的贡献就是所有物品乘起来。
你要求出的是所有选法的贡献和,而物品之间是独立的,每种物品都会作为$1,x$出现各一次。
所以其实就是$(1+x)^n$。把这个东西展开,就是乘法分配律,就得到的是所有方案的和。
(然而写出啦我才知道,这不就是个二项式定理吗我考场上为啥要这么弱智啊)
$x=1:$
也就是说$x^k$那一项消失了。剩下的形式是$\sum\limits_{k=0}^{n} f(k) \binom{n}{k}$
你自然拿多项式没什么办法,所以把它展开:
$\sum\limits_{i=0}^{m} a_i \sum\limits_{k=0}^{n} k^i \binom{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$个作为被钦定过地元素:这是$\binom{n}{j}$
那么你要把$i$次选择分配给这$j$个元素,且每个元素非空。这显然是个第二类斯特林数。
(啊学弟们是不是不知道什么是斯特林数啊,那我失败了啊,我好菜啊)
然而其实只是一个$O(n^2)$递推的东西:$\begin{Bmatrix} n \\ k \end{Bmatrix}$表示将$n$个带编号的球扔进$k$个不带标号桶里且每个桶都有球的方案数。
然而在本道题当中,根据题目含义,桶是带标号的,所以还要乘上一个阶乘。这里的阶乘和上面的组合数形成下降幂$n^{\underline{j}}$
(这个东西学弟们可以当成一个dp来做)
同时你还要考虑原来$n$个里选$k$个的过程:我们知道我们所钦定的$j$个元素一定被选了,没钦定的$n-j$个元素选不选都可以,总方案数是$2^{n-j}$
所以总的方案数是$\sum\limits_{i=0}^{m} a_i \sum\limits_{j=0}^{i} n^{\underline{j}} 2^{n-j} \begin{Bmatrix} i \\ j \end{Bmatrix}$
两层循环暴力枚举完事。组合数的话因为$n$是确定的所以直接搞一个下降幂就好了。
无特殊限制:
$\sum\limits_{k=0}^{n} \binom{n}{k} x^k f(k)$
和上一个部分分一样先拆$f$得到$\sum\limits_{i=0}^{m} a_i \sum\limits_{k=0}^{n} k^i \binom{n}{k} x^k $
和上一个部分分一样我们改变含义去枚举$j$表示被钦定的元素个数,然后接着分析:
其实除了$2^{n-j}$那部分以外,其余都和上面一样可以得到$n^{\underline{j}} \begin{Bmatrix} i \\ j \end{Bmatrix}$
然后因为$x$不再是$1$所以我们不是要计数方案,而是统计方案的贡献和。其中的贡献和第一档部分分一样,选中是$x$没选中是$1$
然后就比较简单了:你钦定的$j$个都一定被选中了是$x^j$,剩下的选不选都行,考虑所有情况就是$(x+1)^{n-j}$
最后的答案是$\sum\limits_{i=0}^{m} a_i \sum\limits_{j=0}^{i} \begin{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 }