组合计数中的隔板法 HDU 1410 PK武林盟主

隔板法解题技巧
本文介绍了使用隔板法解决排列组合问题的三种技巧:添加球数法、减少球数法及先后插入法,并通过具体例子进行说明。

多元一次方程的非负整数解的个数 使用隔板法  x1+..xn=m的非负整数解个数为C(m+n-1,n-1)

在排列组合中,对于将不可分辨的球装入到可以分辨的盒子中而求装入方法数的问题,常用隔板法。隔板法在排列组合中的应用技巧

1.求方程的正整数解的个数。

[分析]

10个球排成一排,球与球之间形成9个空隙,将两个隔板插入这些空隙中(每空至多插一块隔板),规定由隔板分成的左、中、右三部分的球数分别为xyz之值(如下图)。则隔法与解的个数之间建立了一一对立关系,故解的个数为(个)。实际运用隔板法解题时,在确定球数、如何插隔板等问题上形成了一些技巧。下面举例说明。

技巧一:添加球数用隔板法。

2.求方程的非负整数解的个数。

[分析]

注意到xyz可以为零,故上题解法中的限定“每空至多插一块隔板”就不成立了,怎么办呢?只要添加三个球,给xyz各一个球。这样原问题就转化为求的正整数解的个数了,故解的个数为(个)。

[点评]

本例通过添加球数,将问题转化为如例1中的典型隔板法问题。

技巧二:减少球数用隔板法:

3.20个相同的小球放入编号分别为1234的四个盒子中,要求每个盒子中的球数不少于它的编号数,求放法总数。

解法1:先在编号1234的四个盒子内分别放0123个球,剩下14个球,有1种方法;再把剩下的球分成4组,每组至少1个,由例1知方法有(种)。

解法2:第一步先在编号1234的四个盒子内分别放1234个球,剩下10个球,有1种方法;第二步把剩下的10个相同的球放入编号为1234的盒子里,由例2知方法有(种)。

[点评]

两种解法均通过减少球数将问题转化为例1、例2中的典型问题。

技巧三:先后插入用隔板法。

4.为宣传党的十六大会议精神,一文艺团体下基层宣传演出,准备的节目表中原有4个歌舞节目,如果保持这些节目的相对顺序不变,拟再添两个小品节目,则不同的排列方法有多少种?

[分析]

记两个小品节目分别为AB。先排A节目。根据A节目前后的歌舞节目数目考虑方法数,相当于把4个球分成两堆,由例2知有种方法。这一步完成后就有5个节目了。再考虑需加入的B节目前后的节目数,同理知有种方法。故由分步计数原理知,方法共有(种)。

[点评]

对本题所需插入的两个隔板采取先后依次插入的方法,使问题得到巧妙解决。


HDU1410

公式推导: 
设: 
枫之羽为x,氢氧化铜为y 
x需要打n次才能打败y 
y需要打k次才能打败x 
一个回合中,x打y的概率 = y打x的概率 = 0.5 
要x赢,则x必须打n次,而y可以打0次,1次,2次……k-1次,而且最后一次当然必须是x打的,所以(设y打i次),那么一共打n+i次,要在前n+i-1次选i次让x被y打 


所以x赢的概率 = 
C(n+0-1,0)*0.5^n + C(n+1-1,1)*0.5^(n+1) + …… + C(n+i-1,i)*0.5^(n+i)…… 


组合数过大,于是用取对数方法

<span style="font-size:12px;">#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define L __int64
#define M 1005
#define inf 0x3fffffff
int main() {
	int h1, h2, a1, a2, n, k, i;
	double c, res;
	while (~scanf ("%d%d%d%d", &h1, &h2, &a1, &a2))
	{
		n = (h2 + a1 - 1) / a1;
		k = (h1 + a2 - 1) / a2;
		res = pow (0.5, n);
		c = 0;
		for (i = 1; i < k; i++)
		{
			c = c + log10 (n+i-1.0) - log10 (i+0.0);
			res += pow (10.0, c + (n+i)*log10(0.5));
		}
		printf ("%.4f\n", res*100);
	}
    return 0;
}</span>


### HDU OJ 排列组合问题解 排列组合问题是算竞赛中的常见题型之一,涉及数学基础以及高效的实现技巧。以下是关于如何解决此类问题的一些通用方和具体实例。 #### 数学基础知识 在处理排列组合问题时,需要熟悉以下几个基本概念: - **阶乘计算**:用于求解全排列的数量 $ n! = n \times (n-1) \times ... \times 1 $[^4]。 - **组合数公式**:$ C(n, k) = \frac{n!}{k!(n-k)!} $ 表示从 $ n $ 中选取 $ k $ 的方案数[^5]。 - **快速幂运算**:当涉及到模运算时,可以利用费马小定理优化逆元的计算[^6]。 #### 题目推荐与分析 以下是一些典型的 HDU OJ 上的排列组合题目及其可能的解: ##### 1. 基础排列组合计数 - **HDU 2039 近似数** - 描述:给定两个整数 $ a $ 和 $ b $,统计区间内的近似数数量。 - 方:通过枚举每一位上的可能性来构建合数字并计数[^7]。 ```cpp #include <iostream> using namespace std; long long comb(int n, int r){ if(r > n || r < 0)return 0; long long res=1; for(int i=1;i<=r;i++)res=res*(n-i+1)/i; return res; } int main(){ int t,n,k; cin>>t; while(t--){ cin>>n>>k; cout<<comb(n+k-1,k)<<endl; // 组合数应用 } } ``` ##### 2. 动态规划的应用 - **HDU 1028 Ignatius and the Princess III** - 描述:给出正整数 $ m $ 和 $ n $,问有多少种方式把 $ m $ 分成最多 $ n $ 份。 - 方:定义状态转移方程 $ dp[i][j]=dp[i-1][j]+dp[i][j-i] $ 来表示当前总和为 $ j $ 并分成至多 $ i $ 份的情况数目[^8]。 ```cpp #include<bits/stdc++.h> using namespace std; const int MAXN=1e3+5; long long c[MAXN][MAXN]; void init(){ memset(c,0,sizeof(c)); c[0][0]=1; for(int i=1;i<MAXN;i++){ c[i][0]=c[i][i]=1; for(int j=1;j<i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%(1e9+7); } } int main(){ init(); int T,m,n; scanf("%d",&T); while(T--){ scanf("%d%d",&m,&n); printf("%lld\n",c[m+n-1][min(m,n)]); } } ``` #### 总结 针对不同类型的排列组合问题,可以选择合适的工具和技术加以应对。无论是简单的直接计算还是复杂的动态规划模型,都需要扎实的基础知识作为支撑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值