2021“MINIEYE杯”中国大学生算法设计超级联赛(7)04 即 HDU 7047 Link With Balls 组合计数神题

本文介绍了如何解决一个数学建模问题,涉及桶中取球的数量限制。通过转换题意,将能取出指定倍数球的桶与有限制的桶合并,简化成新的桶模型。利用组合计数公式进行化简,最终实现快速计算在给定条件下取球的方法数。文章还提供了C++代码实现,展示了如何在O(1)时间内响应查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录


不幸的我们并没能做出这题,还被别人在四小时五十八分绝杀.

题意

2 n 2n 2n个桶,其中 n n n个里面第 i i i个里面拿出来的球的数量必须是 i i i的倍数,另 n n n个桶里第 i i i个拿出来的球的数量不能超过 n n n,问拿出 m m m个球有多少种方法.对每一个桶都可以拿出 0 0 0个球.

题解

先转换一下题意.
对于两个编号为 i i i的桶,我们考虑能拿出 i i i的倍数个球的桶和最多拿出 i − 1 i-1 i1个球的桶,把这两个桶合成一个桶,惊人的发现这个桶可以取出任意数量的球,并且只有一种取法.
第二个桶还多出一个球,那么整道题可以转换为 n n n个能取任意球的桶和 1 1 1个最多能取 n n n个球的桶.
枚举在最后一个桶中取 x x x个球,则由隔板法可以轻松求出在剩下的桶中取 m − x m-x mx个球的方法总数 C m + n − x − 1 n − 1 C_{m+n-x-1}^{n-1} Cm+nx1n1.
再用组合计数公式化简 ∑ i = 0 n C m + n − i − 1 n − 1 = C n + m m − C m − 1 n \sum_{i=0}^{n}C_{m+n-i-1}^{n-1}=C_{n+m}^{m}-C_{m-1}^n i=0nCm+ni1n1=Cn+mmCm1n,通过预处理阶乘逆元即可 O ( 1 ) O(1) O(1)回答询问.
这个化简比较简单的吧,利用 C n m = C n − 1 m − 1 + C n − 1 m C_n^m=C^{m-1}_{n-1}+C^{m}_{n-1} Cnm=Cn1m1+Cn1m
两边同时加上 C m − 1 n C^n_{m-1} Cm1n不断消去即可得到.

const int yuzu=2e6,mod=1e9+7;
typedef ll fuko[yuzu|10];
fuko jic={1},inv;
ll kasumi(ll a,ll b=mod-2) {
  ll zw=1;
  for (;b;b>>=1,a=a*a%mod) if (b&1) zw=zw*a%mod;
  return zw;
}
ll zhe(int n,int m) {
  return m>n?0:jic[n]*inv[m]%mod*inv[n-m]%mod;
}
int main() {
  int i,t,n,m;
  for (i=1;i<=yuzu;++i) jic[i]=jic[i-1]*i%mod;
  inv[yuzu]=kasumi(jic[yuzu]);
  for (i=yuzu-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
  for (scanf("%d",&t);t--;) {
    scanf("%d%d",&n,&m);
    printf("%lld\n",(zhe(n+m,m)-zhe(m-1,n)+mod)%mod);
  }
}

谢谢大家.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值