奶牛编号 \operatorname{奶牛编号} 奶牛编号
题目链接: SSL比赛 1473 \operatorname{SSL比赛\ 1473} SSL比赛 1473
题目
作为一个神秘的电脑高手, Farmer John 用二进制数字标识他的奶牛。
然而,他有点迷信,标识奶牛用的二进制数字,必须只含有 K K K 位 “ 1 ” ( 1 < = K < = 10 ) “1” (1 <= K <= 10) “1”(1<=K<=10) 。 当然,每个标识数字的首位必须为 “ 1 ” “1” “1” 。
FJ 按递增的顺序,安排标识数字,开始是最小可行的标识数字(由 “ 1 ” “1” “1” 组成的一个K位数)。
不幸的是,他没有记录下标识数字。请帮他计算,第 N N N 个标识数字 ( 1 < = N < = 1 0 7 ) (1 <= N <= 10^7) (1<=N<=107) 。
输入
第 1 1 1 行:空格隔开的两个整数, N N N 和 K K K 。
输出
如题,第 N N N 个标识数字
样例输入
7 3
样例输出
10110
思路
这道题是一道组合数。
先看有多少位,再枚举 1 1 1 的数量,通过看组合数找到 i i i 的位置,中间的地方就补 0 0 0 。
代码
#include<cstdio>
#define ll long long
using namespace std;
ll n, k, now, num, number, tmp;
ll C(ll X, ll Y){//组合数
if (!Y) return 1;
ll an = 1;
for (ll i = X; i >= X - Y + 1; i--)
an *= i;
for (ll i = 1; i <= Y; i++) an /= i;
return an;
}
ll read() {//快读
ll an = 0, zhengfu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') zhengfu = -zhengfu;
c = getchar();
}
while (c >= '0' && c <= '9') {
an = an * 10 + c - '0';
c = getchar();
}
return an * zhengfu;
}
int main() {
n = read();
k = read();//读入
now = k - 1;
tmp = C(now, k - 1);
while (tmp + num < n) {//求出位数
num += tmp;
tmp = C(++now, k - 1);
}
putchar('1');
number = now;
n -= num;
for (k--; k; k--) {//还剩多少个1
now = k - 1;
num = 0;
tmp = C(now, k - 1);
while (tmp + num < n) {//找到下一个1
num += tmp;
tmp = C(++now, k - 1);
}
for (ll i = 1; i <= number - now - 1; i++)//补0
putchar('0');
putchar('1');//输出1
number = now;
n -= num;
}
for (ll i = 1; i <= number; i++)
putchar('0');//输出
return 0;
}