组合数学or not ---- n选k有重
模板问题:
1. 取物品 (comb.pas/c/cpp)
【问题描述】 现在有n个物品(有可能相同),请您编程计算从中取k个有多少种不同的取法。
【输入】 输入文件有两行,第一行包含两个整数n,k(2<=n<=30,0<=k<=n)。第二行,包含n个整数表示物品的编号(范围1..1000)。编号相同的物品看作同一种物品。
想想看,组合数学中有这样的模型吗?答案是,肯定会有的.但是因为这个问题的灵活性,还没有通项公式.
想象当每个数都不同时,这个问题就变成了{n \choose k}(即\text{C}^{k}_{n}).如果只有一种物体呢?显然是1种可能.每种物体都大于等于k?就是n^k,因为k次选择每次都可以选1~n.
但是这里是一般化的情况:(RT)
自然,对于这个数据搜索只能勉强卡过.那么递推呢?递推一般对于解决排列解决问题很有用.那么我们设
f\left[ i,p\right]为前i种选p个的方案数,那么
f[i,p]=\sum_{k=0}^{\text{min}\left( N[i],p\right)}f[i-1,p-k]\text{ while here }p\le \sum_{j=1}^{i}N[j]
初始状态\forall i \in [1,n],f[i,0]=1(这个很重要)
自然,我们可以用滚动数组优化空间,因为所有f[i,k]只与f[i-1,d]有关,且d\le k,这时可以用类似于优化背包问题的办法.这个时间复杂度为\text{O}\left( nkp\right)但是注意这里p会比n大很多.
再考虑优化.注意到sum是连续的,即可用前缀和优化.那么时间复杂度小了一个p.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步