USACO Stringsobits 解题报告

来源:互联网 发布:windows office 密钥 编辑:程序博客网 时间:2024/04/30 11:09

可以直接移步这里:大神的代码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: thestor1LANG: 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 notationtmp = 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;}


原创粉丝点击