【USACO题库】3.2.2 Stringsobits__01串

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

输入要求
共一行,用空格分开的三个整数N,L,I。

样例输入
5  3  19

输出要求
共一行,输出满足条件的第I大的二进制数。

样例输出
10011


这题之前我做了很久都没有做出来,后来去看了某人的题解后才做出来。

我们先设一个数组F,F[i,j]表示长度为i且当前序列1的个数 小于 j的所有方案数。
每一位都有0或1两种可能,对应F[i-1,j]和F[i-1,j-1]两种情况。
状态转移方程:
F[i,j]=F[i-1,j-1]+F[i-1,j] (i=1~n j=1~n)
初始化:
F[i,0]=1 (i=0~n)
F[0,i]=1 (i=1~l)

求出了F数组后,我们就可以通过F数组求出最后的结果。
用样例来说明:
?0011,现在要把?处补上,有0和1两种可能。
那么到底是0还是1呢?
我们要求第i位的数字,就要看它的后一位的结果是多少。
例如要求第5位的数字,我们就要看第4位的结果。
因为F[4,3]=15,而19>15,所以这一位是1。
F[4,3]=15,意味着已0和1开头的长度为5且1的个数小于3的情况有15种,而要求的结果19大于(一定是大于,因为第15种开头还是0)15,所以是1。
之后把19减去15,接着往下计算。 以此类推。

鉴于此题较难,所以直接上代码:
var
        f:array[0..31,0..31] of longint;
        n,l,i,j:longint;
        p:int64;
begin
        readln(n,l,p);

        for i:=0 to n do
        f[i,0]:=1;
        for i:=1 to l do
        f[0,i]:=1;

        for i:=1 to n do
                for j:=1 to n do
                f[i,j]:=f[i-1,j-1]+f[i-1,j];

        for i:=n-1 downto 0 do
        if f[i,l]<p then
        begin
                p:=p-f[i,l];

                dec(l);

                write(1);
        end
        else
        write(0);

        writeln;
end.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值