1046. 【USACO题库】3.2.2 Stringsobits__01串

题目:

题目描述

考虑排好序的N(N<=31)位二进制数。
你会发现,这很有趣。因为他们是排列好的,
而且包含所有可能的长度为N且含有1的个数小于等于L(L<=N)的数。
你的任务是输出第I(1<=I<=长度为N的二进制数的个数)大的,
长度为N,且含有1的个数小于等于L的那个二进制数。

输入

从文件 kimbits.in 中读入数据。
共一行,用空格分开的三个整数N,L,I。

输出

输出到文件 kimbits.out 中。
共一行,输出满足条件的第I大的二进制数。

样例输入

5 3 19

样例输出

10011

思路

使用动态规划的方法去做:
状态转移方程:
if(j<=i) f[i][j]=f[i-1][j-1] + f[i-1][j];
else f[i][j]=f[i][i];

f[i][j] 是表示长度是i, 1的个数是j的个数
 for (int i=0;i<=N;i++)f[i][0] = f[0][i] = 1; # dp的初始化
 # dp的初始化详解
	(1)因为1的个数是0的字符串不管长度是多少, 一定是只有1(比如00000, 长度是5, 只有01)

	(2)因为长度是0的字符串肯定是只有一个(空串"")
# dp的中间部分详解
	(1)因为不管是长度还是个数, 最大都是N, 所以这是循环的条件
	(2)请看下边的表格

f[0][0] = 1
f[1][0] = 1 f[1][1] = 1
f[2][0] = 1 f[2][1] = 2 f[2][2] = 1
f[3][0] = 1 f[3][1] = 3 f[3][2] = 3 f[3][3] = 1
f[4][0] = 1 f[4][1] = 4 f[4][2] = 6 f[4][3] = 4 f[4][4] = 1
f[5][0] = 1 f[5][1] = 5 f[5][2] = 10 f[5][3] = 10 f[5][4] = 5 f[5][5] = 1
就是一个组合数的计算

关键概念
数组 f: 这个数组通常是用来存储组合数,也就是 
f[i][L]
f[i][L] 表示从 i 位中选择 L 个 1 的所有组合方式。你在计算组合数的时候,可以用动态规划来填充这个表。

I 和 L:

I 是一个整数,它表示在可能的组合中,我们希望找到的第 I 个组合。
L 是当前剩余的 1 的数量。
二进制数: 在这个上下文中,我们希望构造一个由 01 组成的二进制数。

逐位构造二进制数的过程
假设你希望从最高位(第 N 位)到最低位(第 1 位)逐位构造一个符合条件的二进制数。这里是详细步骤的解释:

1. 初始化
设定一个长度为 N 的二进制数 result,用于存储构造后的二进制数。
设定初始的 I 和 L。
2. 从高位到低位逐位构造
循环从 N 到 1(高位到低位):

for位从N到1
在每一位:
检查以 0 开头的组合数:
通过查表来查看以 0 开头的组合数,使用 f[i-1][L]。
如果 I 大于 f[i-1][L],说明第 I 个组合所在位置一定是在以 0 开头的组合之后,因此当前位置必须是 1。
将 result 的这一位设置为 1。
更新 I 为 I - f[i-1][L](因为我们把以 0 开头的组合数都排除了)。
还需要减少剩余的 1 的数量:L = L - 1(因为我们用了一个 1)。
如果 I 小于或等于 f[i-1][L],那么当前位置设置为 0。
这表明当前组合是在以 0 开头的组合中。
3. 结束构造
最终,经过所有的位的判断和设置后,你就可以得到一个完整的符合条件的二进制数。

举个例子
假设你有 5 位(N=5),并且要选择 31(L=3),并希望找到第 10 个组合。

计算组合数 f[i][L]:

例如 f[4][3] 对应于从 4 位中选择 31 的组合数为 4。
f[4][2] 对应于从 4 位中选择 21 的组合数为 6。
从第 5 位开始:

检查 f[4][3],发现 I(10)大于 f[4][3]4)。所以当前位为 1,更新 I 为 10 - 4 = 6,并减去一个 1,L=2。
检查第 4 位(现在的 L=2):

对于第 4 位,f[3][2]3,发现 I(6)大于 f[3][2]3)。位置为 1,更新 I 为 6 - 3 = 3,L=1。
检查第 3 位(现在的 L=1):

对于第 3 位,f[2][1]2,发现 I(3)大于 f[2][1]2)。位置为 1,更新 I 为 3 - 2 = 1,L=0。
检查第 2 位(L=0):

f[1][0]1,发现 I(1)等于 f[1][0]1)。位置为 0。
检查第 1 位:

因为所有的 1 都用完了,当前位置为 0。
最终构造出的结果可能是 1110011010 之类的组合,具体取决于选择。

你可能感兴趣的:(粉丝才可以看的NC题解,C++,算法)