奶牛编号

D e s c r i p t i o n Description Description

作为一个神秘的电脑高手,Farmer John 用二进制数字标识他的奶牛。
然而,他有点迷信,标识奶牛用的二进制数字,必须只含有K位“1” (1 <= K <= 10)。 当然,每个标识数字的首位必须为“1”。
FJ按递增的顺序,安排标识数字,开始是最小可行的标识数字(由“1”组成的一个K位数)。
不幸的是,他没有记录下标识数字。请帮他计算,第N个标识数字 (1 <= N <= 10^7)。

I n p u t Input Input

第1行:空格隔开的两个整数,N和K。

O u t p u t Output Output

如题,第N个标识数字

S a m p l e Sample Sample I n p u t Input Input
7 3
S a m p l e Sample Sample O u t p u t Output Output
 10110

H i n t Hint Hint

见题

T r a i n Train Train o f of of T h o u g h t Thought Thought

就是想先找出答案的位数,然后再从当前位数开始找,知道找到第n位
首先找出答案的位数
这个数的要求其实只有第一位是1
所以假设当前位数是5,则位数有5的数有 C 5 − 1 k − 1 C^{k - 1}_{5 - 1} C51k1
然后我们可以将这个数从1位一直累加,知道再加一次就会大于或等于 n n n
当前的位数就是答案的位数了
最后求这个数
第一位已经确认为1了
我们从第二位开始
t + C h m − l < n t+C^{m - l}_{h}<n t+Chml<n
我这里h是还可以填多少个1
t是当前最小为第几个
m为答案的位数
l是当前位置(还未填)
所以 m − l m-l ml表示剩余的位置-1
所以这个式子表示若第 l l l位填0的话
后面的还有多少种填法
若这些加上当前最小还是没有n高
就可以直接填1了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;

ll n, m, l, t, k, tot, h;
ll C[101000][1005];
int flag;

int main()
{
	scanf("%lld%lld", &n, &k);
	if(k == 1)
	{
		putchar(49);
		for(int i = 1; i < n; ++i) 
			putchar(48);
		return 0;
	}
	for(int i = 0; i <= 10005; ++i)
		C[i][0] = 1;
	for(int i = 1; i <= 10000; ++i)
		for(int j = 1; j <= 10; ++j)
			C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
			
	l = 0, t = 0, tot = 1, flag = 0;
	
	while(t < n)t += C[k + l - 1][k - 1], l++;//累加
	
	if(t > n)l--, t -= C[k + l - 1][k - 1];//防止超过了n
	
	m = k + l;//k为1的数量,l为0的数量
	putchar(49);
	l = 2, h = k - 1;
	while(t <= n && l <= m)
	{
		if(t + C[m - l][h] < n && h)//还要判断还有没有1可以填
		{
			t += C[m - l][h];
			putchar(49); h--;
		}
		else putchar(48);
		l++;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值