可以直接移步这里:大神的代码http://belbesy.wordpress.com/2012/08/13/usaco-3-2-2-stringsobits/
这道题让求第I个N位数,要求这些数的二进制表达中1的个数小于L。
刚开始用暴力解法,从1开始递增,算每个数的二进制表达中1的个数,并计数。不出所料地通不过后面的大测试点。即使用了快速计算二进制中1的个数的方法(见代码)。
在看了大神的代码后开始使用动态规划的方法。
cnt[n][k] = cnt[n - 1][k] + cnt[n - 1][k - 1]
这个表达式的左侧表示n位二进制数其中1的个数小于等于k的个数。右边的表达式把这样的数分为两类:第n位为0的(第一部分)和第n位为1的(第二部分,剩下的n-1位至多有k-1个1)。
最后计算要求的数的时候从左往右逐位判断:
比如第n位,看后面n-1位满足条件的数的个数(cnt[n-1][k])是否大于I,如果是,则第n位是0,继续在后面n-1位组成的数中找(n-1位中有k个1的第I个数);如果不是,则说明要找的数第n位是1,把n位是0的满足条件的数的个数(cnt[n-1][k])减去(因为这些数小,排在前面),就是这个数在n位是1的满足条件的数中的排位,相当于接下来在n-1位中k-1个1的第I-cnt[n-1][k]个数。
代码如下,前面两个函数为求一个数中的二进制表达中1的个数的方法,第一个快于第二个,但都超时,因而用不上。
/*
ID: thestor1
LANG: C++
TASK: kimbits
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <algorithm>
using namespace std;
int bitcount(unsigned int n) {
/* works for 32-bit numbers only */
/* fix last line for 64-bit numbers */
register unsigned int tmp;
//octal notation
tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111);
return ((tmp + (tmp >> 3)) & 030707070707) % 63;
}
inline int cntones(int num)
{
int cnt = 0;
while(num > 0)
{
num &= num - 1;
cnt++;
}
return cnt;
}
string tobinary(unsigned int num, unsigned int width)
{
string str;
int w = 0;
while(num > 0)
{
str.push_back('0' + (num & 0x01));
num >>= 1;
w++;
}
string ret;
for(int i = w; i < width; ++i)
{
ret.push_back('0');
}
for(int i = str.length() - 1; i >= 0; --i)
{
ret.push_back(str[i]);
}
return ret;
}
int main()
{
FILE *fin = fopen ("kimbits.in", "r");
FILE *fout = fopen ("kimbits.out", "w");
//freopen("log.txt", "w", stdout);
unsigned int N, L, I;
fscanf(fin, "%u%u%u", &N, &L, &I);
unsigned int cnt[32][32] = {{0}};
for(unsigned int n = 0; n <= N; ++n)
{
cnt[n][0] = 1;
cnt[0][n] = 1;
}
for(unsigned int n = 1; n <= N; ++n)
{
for(unsigned int k = 1; k <= L; ++k)
{
cnt[n][k] = cnt[n - 1][k] + cnt[n - 1][k - 1];
}
}
unsigned int n = N, k = L;
while(n > 0)
{
fprintf(stdout, "cnt[%u - 1][%u] = %u, I = %u\n", n, k, cnt[n - 1][k], I);
if(cnt[n - 1][k] >= I)
{
fprintf(stdout, "%u\n", I);
fprintf(fout, "0");
n--;
}
else
{
fprintf(fout, "1");
I -= cnt[n - 1][k];
n--;
k--;
}
}
fprintf(fout, "\n");
return 0;
}