USACO Section 3.2 PROB Stringsobits

题目:Stringsobits
Kim Schrijvers

Consider an ordered set S of strings of N (1 <= N <= 31) bits. Bits, of course, are either 0 or 1.

This set of strings is interesting because it is ordered and contains all possible strings of length N that have L (1 <= L <= N) or fewer bits that are `1'.

Your task is to read a number I (1 <= I <= sizeof(S)) from the input and print the Ith element of the ordered set for N bits with no more than L bits that are `1'.


PROGRAM NAME: kimbits
INPUT FORMAT
A single line with three space separated integers: N, L, and I.
SAMPLE INPUT (file kimbits.in)

5 3 19

OUTPUT FORMAT
A single line containing the integer that represents the Ith element from the order set, as described.
SAMPLE OUTPUT (file kimbits.out)

10011


分析:

最先想到的是采用filtering,即从数字0 -  (2^N-1), 依次判断该数字转换成位串后是否满足条件----含1的个数小于等于L。直到找到第I个满足该条件的数。

但是这样的时间复杂度为 O(N * 2^N), 题目中N最大为31,估计运行时间要超过1s。

为了加快速度,可采用generating,即直接去生成想要的那个位串。方法是先确定第一位是0还是1, 然后转化为子问题进行递归。 其实可以计算出第一位

是0时(或1时)有多少个满足条件的位串(求组合数)。求出来之后就直到第一位是0还是1了,然后进行递归。


代码:C++

/*
ID: randyji1
PROG: kimbits
LANG: C++
*/

#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cassert>
using namespace std;


ifstream fin("kimbits.in");
ofstream fout("kimbits.out");

int strLen, maxNOfOnes;
unsigned long ith;
void getInput() {
    fin >> strLen >> maxNOfOnes >> ith;
}

unsigned long getComb(int n, int m) {
    m = min(m, n-m);
    double result = 1;
    for(int i = n-m+1; i <= n; i++)
        result *= i;
    for(int j = 1; j <= m; j++)
        result /= j;
    return result;
}


unsigned long getCount(int n, int maxNOfOnes) {
    unsigned long result = 0;
    int upper = min(n, maxNOfOnes);
    for(int i = 0; i <= upper; i++) {
        result += getComb(n, i);
    }
    return result;
}

void getFirstBit(int strLen, int maxNOfOnes, unsigned long ith) {
    //cout << strLen << " " << maxNOfOnes << " " << ith << endl;
    if(strLen == 1) {
        assert(ith == 1 || ith == 2);
        if(ith == 1) {
            fout << '0' << endl;
        } else {
            assert(maxNOfOnes >= 1);
            fout << '1' << endl;
        }
        return;
    }

    if(maxNOfOnes == 0) {
        while(strLen--) {
            fout << '0';
        }
        fout << endl;
        return;
    }
    
    //计算以0开头的合法的有多少个
    unsigned long count = getCount(strLen-1, maxNOfOnes);

    if(ith <= count) {
        fout << '0';
        getFirstBit(strLen-1, maxNOfOnes, ith);
    } else {
        fout << '1';
        getFirstBit(strLen-1, maxNOfOnes-1, ith-count);
    }
}

int main() {
   
   assert(fin && fout);
   getInput();
   getFirstBit(strLen, maxNOfOnes, ith);

   return 0;
}

注:C++没有求组合数的标准库(还是Matlab方便啊)。我自己写了一个,采用了最笨的方法,直接算,注意可能溢出。官方答案中采用了dynamic programming 来求。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值