西南交大峨眉校区INT杯2020-D.排列计数【排列组合+经典隔板法】

这篇博客介绍了如何使用组合计数和隔板法解决一类数学问题,即在限制公牛之间必须有特定数量母牛的情况下,计算不同排列方式的数量。通过分析最多公牛数量,枚举公牛方案并应用隔板法,得出最终答案。文章详细解释了思路和算法,并给出了AC代码实现,涉及组合数的模逆运算,适合对算法和数学有兴趣的读者阅读。
摘要由CSDN通过智能技术生成

排列计数

Description

正所谓“牛如其主”,XHK家里养的N只牛牛因为身形健硕所以被邀请去参加集会里的展示活动,这些牛可以是公牛,也可以是母牛。牛们要站成一排,但是公牛是好斗的,为了避免公牛闹出乱子,任意两只公牛之间至少要有K只母牛。

现在请计算一共有多少种排队的方法,所有公牛可以看成是相同的,所有母牛也一样,答案对5000011取模。

Input

一行,输入两个整数N和K

Output

一个整数,表示排队的方法数。

Sample Input

4 2

Sample Output

6

思路:

1.首先,最多有多少只公牛其实很好求,就是n/(k+1)向上取整,将一只公牛和k只母牛放到一起计算,公牛最多就有n/(k+1)向上取整。

2.其次,就可以枚举放不同公牛的方案数,设当前枚举的公牛为x只,母牛必须固定的位置是x只公牛之间(x-1个空格)的y = k*(x-1)只母牛。现在就等于x+1个位置放n-y-x只牛,允许为空,有多少种方案数,这儿就要引入隔板法了,隔板法先放下面。所以方案数为:
∁ \complement x + 1 − 1 n − y − x + x + 1 − 1 x+1-1 \atop n-y-x+x+1-1 nyx+x+11x+11 ∁ \complement x n − k ∗ ( x − 1 ) x \atop n-k*(x-1) nk(x1)x (注:这儿写的比较细,耐心看肯定能懂);

3.最后求出枚举过不同公牛的方案总数,题目数据很大,所以要用乘法逆元来求组合数。

隔板法:

应用隔板法必须满足3个条件:   
(1) 这n个元素必须互不相异;
(2) 所分成的每一组至少分得1个元素;
(3) 分成的组别彼此相异。

1:假设有n个苹果,放到m个盘子中,每个盘子至少有1个,求总方案数。
相当于有m - 1个板子,将n个苹果分开。这m-1个板子只能放到n-1个间隔中,所以就是 ∁ \complement m − 1 n − 1 m-1 \atop n-1 n1m1;

2:假设有n个苹果,放到m个盘子中,盘子可以为空,求总方案数。
我们可以将问题转化为将n+m个苹果,放到m个盘子中,每个盘子至少有1个,求总方案数。所以就是 ∁ \complement m − 1 n + m − 1 m-1 \atop n+m-1 n+m1m1;

AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 5000011;
ll fast_power(ll a, ll b) {
	ll ans=1;
	while (b > 0) {
		if(b & 1) {
           ans = ans * a % mod;
		}
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}
ll calc(ll m, ll n)
{
	ll sum1 = 1, sum2 = 1;
	if(m > n - m) m = n - m;
	for(ll i = 1; i <= m; i++) {
        sum1 *= (n - i + 1);
        sum1 %= mod;
        sum2 *= i;
	    sum2 %= mod;
	}
	return (sum1 * fast_power(sum2, mod-2)) % mod;
}
void solve() {
    ll ans = 0;
	int n, k;
	cin >> n >> k;
	//maxn表示最多有多少头公牛
	int maxn = (n - 1) / (k + 1) + 1;
	for(int i = 1;i <= maxn; i++){
        //利用经典的隔板法。m个球放到n个盒子里的情况,允许盒子为空的情况类似。
        ans=(ans % mod + calc(i, n - k * i + k) % mod) % mod;
	}
	cout << (ans + 1) % mod;
}
int main() {
    solve();
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空皓月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值