杨辉三角(组合数)+排列组合

洛谷P2638

一道虐我的数学题,今天太累了,就简单聊聊思想核心
题目如下:

特斯拉公司的六位密码被轻松破解后,引发了人们对电动车的安全性能的怀疑。李华听闻后,自己设计了一套密码:假设安全系统中有n个储存区,每个储存区最多能存储存2个种类不同的信号(可以不储存任何信号)。有0和1这两种信号,其中0有a个,1有b个,单独一个0或1算一个信号。现要将这些信号储存在储存区中,0和1可以不用全部储存,一种不同的储存方案经过李华处理后就将是一串不同的密码。现在给出n,a,b,求可能的不同储存方案的个数。

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ull unsigned long long
#define N 1000
ull s[N][N];
int main()
{
	ull n, a, b;
	cin >> n >> a >> b;
	for(int i=1;i<=60;i++)
		for (int j = 1; j <= i; j++)
		{
			if (j == 1 || j == i)s[i][j] = 1;
			else
			{
				s[i][j] = s[i - 1][j] + s[i - 1][j - 1];
			}
		}
	ull ans = 0;
	for(int i=0;i<=a;i++)
		for (int j = 0; j <= b; j++)
		{
			ans += s[n + i][n] * s[n + j][n];
		}
	cout << ans << endl;

	return 0;
}

先聊聊杨辉三角,我们有知道杨辉三角是长啥样的,但都不知到杨辉三角的性质,其中能够用来解决本题的是:杨辉三角中第 i 行,第 j 列的数就等于 从 i-1 个数中砸出 j-1 个数的方案,也就是C(j-1,i-1)。
所以我们可以把代码写成这样:

#include<bits/stdc++.h>
using namespace std;
int cb[50][50]; 
int main()
{
	for(int i=0;i<10;i++)
	{
		cb[i][0]=cb[i][i]=1;
		for(int j=1;j<i;j++)
		{
			cb[i][j]=cb[i-1][j-1]+cb[i-1][j];
		}
	}
	for(int i=0;i<10;i++)
	{
	cout<<endl; 
	for(int j=0;j<=i;j++)
	{
		cout<<cb[i][j]<<' ';
	}
    }
	return 0;
 } 

这样如果要调用C(n,m),就直接输出cb[n][m]就行了。


聊回本题思路,只能说数学题真是妙啊!
隔板法 高中数学全还给老师了

我们先退一步。k 个球分给 n 个盒子。我们假设,题目要求变为每个盒子至少要分得一个球,如何解决呢?
k 个球之间形成了 k-1 个间隙,我们将 n-1 个隔板插入间隙中,隔板就将球分为了 k份,符合假设。这样从 k−1 个间隙中选出 n-1 个插入隔板,再进行计算组合数。
但是现在要解决的情况是盒子可以分不到球。这样我们通过一步化归,转换为上面的情况:添加 n个球,使每个盒子至少有一个球。这样分完后只要将每个盒子多拿的一个球收回,便回到原情况了。

大佬的思路妙就妙在增添n个隔板上。这样就可以制造出一个无论什么情况都可以用C的情况,又不会影响答案的精度。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值