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}
C5−1k−1
然后我们可以将这个数从1位一直累加,知道再加一次就会大于或等于
n
n
n
当前的位数就是答案的位数了
最后求这个数
第一位已经确认为1了
我们从第二位开始
若
t
+
C
h
m
−
l
<
n
t+C^{m - l}_{h}<n
t+Chm−l<n
我这里h是还可以填多少个1
t是当前最小为第几个
m为答案的位数
l是当前位置(还未填)
所以
m
−
l
m-l
m−l表示剩余的位置-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;
}