Stringsobits01串
描述
考虑排好序的N(N<=31)位二进制数。
他们是排列好的,而且包含所有长度为N且这个二进制数中1的位数的个数小于等于L(L<=N)的数。
你的任务是输出第i(1<=i<=长度为N的二进制数的个数)小的(注:题目这里表述不清,实际是,从最小的往大的数,数到第i个符合条件的,这个意思),长度为N,且1的位数的个数小于等于L的那个二进制数。
(例:100101中,N=6,含有位数为1的个数为3)。
格式
PROGRAM NAME: kimbits
INPUT FORMAT:
(file kimbits.in)
共一行,用空格分开的三个整数N,L,i。
OUTPUT FORMAT:
(file kimbits.out)
共一行,输出满足条件的第i小的二进制数。
SAMPLE INPUT
5 3 19
SAMPLE OUTPUT
10011
【分析】:动态规划:f[i][j]表示长度为i的串且1的个数不超过j的个数。f[i][j]=f[i-1][j]<取0,即从长度为i-1的串且1个数为j转移来>+f[i-1][j-1]<取1,即从长度为i-1的串且1个数为j-1转移来<要再填个1>>。最后输出:设所求串为S,假设S的位中最高位的1在自右向左第i+1位,那么必然满足f[i,j]<I,f[i+1,j]>=I<即长度i且1的个数不超过j的串的个数小于I个,且长度为i+1的串个数大于I个,这是常理,不然没有答案>,因为有f[i,j]个串第i+1位上为0,所以所求的数的后i位就应该是满足"位数为i且串中1不超过L-1个"这个条件的第I-f[i,j]个数。则最终输出方法:若当前输出位为i,可输出的1个数为j,先判断f[i][j]是否小于I,如果是就输出1,并将I减去f[i][j],否则输出0.
【代码】:
/*
ID:csyzcyj1
PROG:kimbits
LANG:C++
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAX 32
long long N,L,I,f[MAX][MAX];
void output(long long floor,long long one,long long i)
{
if(floor==0) return;
if(f[floor-1][one]<i)
{
printf("1");//设所求串为S,假设S的位中最高位的1在自右向左第i+1位,那么必然满足f[i,j]<I,f[i+1,j]>=I,这样的i是唯一的,所以S的1在从右至左第i+1位.
output(floor-1,one-1,i-f[floor-1][one]);//因为有f[i,j]个串第i+1位上为0,所以所求的数的后i位就应该是满足"位数为i且串中1不超过L-1个"这个条件的第I-f[i,j]个数。
}
else
{
printf("0");
output(floor-1,one,i);
}
}
void dp()//f[i,j]:长度为i的串,1的个数不大于j的个数
{
for(int i=0;i<=N;i++)
f[i][0]=1;
for(int i=0;i<=L;i++)
f[0][i]=1;
for(int i=1;i<=N;i++)
for(int j=1;j<=L;j++)
f[i][j]=f[i-1][j]+f[i-1][j-1];//分别表示在当前位加上0和加上1时的两种状况
}
int main()
{
freopen("kimbits.in","r",stdin);
freopen("kimbits.out","w",stdout);
scanf("%lld%lld%lld",&N,&L,&I);
dp();
output(N,L,I);
printf("\n");
//system("pause");
return 0;
}