USACO Stringsobits

1、本题真的不擅长。。。看题解做的。首先用dp的方法求出位数为i,至多j个1的数的个数,然后再利用类似逆康托展开的方法,输出数字。

2、注意I最多可达2147483648,故应该采用unsigned int保存。

/*
ID:mrxy564
PROG:kimbits
LANG:C++
*/
#include<cstdio>
using namespace std;
int f[35][35];
int main(){
 freopen("kimbits.in","r",stdin);
 freopen("kimbits.out","w",stdout);
    int N,L;
 unsigned int I;
 scanf("%d%d%u",&N,&L,&I);
 for(int k=0;k<=L;k++)
      f[0][k]=1;
 for(int k=0;k<=N;k++)
   f[k][0]=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];
 while(N){
    if(I<=f[N-1][L]) printf("0");
    else {printf("1");I-=f[N-1][L];L--;}
    N--;
 }
    printf("\n");
 return 0;
}

官方题解:

Suppose we knew how to calculate the size of the set of binary numbers for a given nbits and nones. That is, suppose we have a function sizeofset(n, m) that returns the number of n-bit binary numbers that have at most m ones in them.

Then we can solve the problem as follows. We're looking for the ith element in the set of size n with m bits. This set has two parts: the numbers the start with zero, and the numbers that start with one. There are sizeofset(n-1, m) numbers that start with zero and have at most m one bits, and there are sizeofset(n-1, m-1) numbers that start with one and have at most m one bits.

So if the index is less than sizeofset(n-1, m), the number in question occurs in the part of the set that is numbers that start with zero. Otherwise, it starts with a one.

This lends itself to a nice recursive solution, implemented by "printbits".

The only difficult part left is calculating "sizeofset". We can do this by dynamic programming using the property described above:

	sizeofset(n, m) = sizeofset(n-1, m) + sizeofset(n-1, m-1)

and sizeofset(0, m) = 1 for all m. We use double's throughout for bits, but that's overkill given the rewritten problem that requires only 31 bits intead of 32.

/*
PROG: kimbits
ID: rsc001
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

FILE *fout;

/* calculate binomial coefficient (n choose k) */
double sizeofset[33][33];

void
initsizeofset(void)
{
	int i, j;

	for(j=0; j<=32; j++)
		sizeofset[0][j] = 1;

	for(i=1; i<=32; i++)
	for(j=0; j<=32; j++)
		if(j == 0)
			sizeofset[i][j] = 1;
		else
			sizeofset[i][j] = sizeofset[i-1][j-1] + sizeofset[i-1][j];
}

void
printbits(int nbits, int nones, double index)
{
	double s;

	if(nbits == 0)
		return;

	s = sizeofset[nbits-1][nones];
	if(s <= index) {
		fprintf(fout, "1");
		printbits(nbits-1, nones-1, index-s);
	} else {
		fprintf(fout, "0");
		printbits(nbits-1, nones, index);
	}
}

void
main(void)
{
	FILE *fin;
	int nbits, nones;
	double index;

	fin = fopen("kimbits.in", "r");
	fout = fopen("kimbits.out", "w");
	assert(fin != NULL && fout != NULL);

	initsizeofset();
	fscanf(fin, "%d %d %lf", &nbits, &nones, &index);
	printbits(nbits, nones, index-1);
	fprintf(fout, "\n");

	exit(0);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值