【USACO题库】3.2.2 Stringsobits__01串

来源:互联网 发布:动画生成软件 编辑:程序博客网 时间:2024/06/06 01:18

题目描述


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

INPUT FORMAT

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

SAMPLE INPUT (file kimbits.in)
5  3  19

OUTPUT FORMAT
共一行,输出满足条件的第I大的二进制数。
SAMPLE OUTPUT (file kimbits.out)

10011


这道题很难,构思巧妙,先用dp求出所要求f[i,j]前i位1的个数不大于j的方案数,然后便是print了。

先讲一下如何计算f[i,j]。

f[i,j]表示前i位,1的个数不大于j的方案数。

显然:f[i,j]=f[i-1,j]+f[i-1,j-1]

f[i-1,j]表示当前第i位以0开头所得到的方案数,f[i-1,j-1]表示当前第i位以1开头得到的方案数。


如何根据得到的f[i,j]来print呢?如果当前我要确定第i位,那么肯定要看f[i-1]集合中的值判断,例如我当前确定第5位,前4位不超过3个1的方案数为15,而我现在要求第19位,则第5为1,因为19>15,为什么呢?因为第5位可能为0,1,而为0的占了15个,为1的开头也是占15个,显然19属于为1开头的数,所以输出1,输出1的同时还要更新数据即可。输出0就什么也不用更新。

更新数据是指:当前第19位要减去15,3个1要变为2个1,以更新完的数据去得到第i+1个数才能是正确的。

以此类推...

代码:

var        f:array[0..31,0..31] of int64;        i,j:longint;        n,l,k:int64;procedure print;begin        for i:=n-1 downto 0 do                if f[i,l]<k then                begin                        write(1);                        dec(k,f[i,l]);                        dec(l);                end                else                write(0);        writeln;end;begin        readln(n,l,k);        fillchar(f,sizeof(f),0);        for i:=0 to n do                f[i,0]:=1;        for i:=0 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]+f[i-1,j-1];        print;end.
















===============================================分界线====================================================

好了,将近半年多了,重返此题,确实大不一样,能凭自己的能力推出状态想到解法了,可是就是有些粗心,边界竟然连续两次弄错,f[0,i]没有赋值为1导致最后一位的计算错误,哎╮(╯▽╰)╭,继续加油吧~

2 0
原创粉丝点击