【数学】奶牛编号(jzoj 2932)

奶牛编号

jozj 2932

题目大意

求出有m个1的01串中字典序第n大的字典序

输入样例

7 3

输出样例

10110

数据范围

1 ⩽ M ⩽ 10 1 \leqslant M \leqslant 10 1M10
1 ⩽ N ⩽ 1 0 7 1 \leqslant N \leqslant 10^7 1N107

解题思路

我们先从01串长度入手:
先对 m = 1 m = 1 m=1的特判
然后 m ⩾ 2 m \geqslant 2 m2的我们用组合数来判断当前位是否为1(详情见代码)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll n, m, a, b, p;
int main()
{
	scanf("%lld%lld", &n, &m);
	if (m == 1)//特判
	{
		printf("1");
		for (int i = 1; i < n; ++i)
			printf("0");
		return 0;
	}
	for (ll i = 5000; i > 0; --i)//C_(5000,2)>10^7,已经足够了
		if (!m) printf("0");
		else
		{
			a = b = 1;//c_(i,m)就是这一位是0的组合数
			for (ll j = m; j > 1; --j)//组合数公式的分母部分
				b *= j;
			for (ll j = i; j > i - m && a / b < n; --j)//分子部分,a/b<n是防止数据过大
				a *= j;
			if (a / b < n)//如果这一位是1那n就比C_(i,m)大
			{
				printf("1");
				m--;
				n -= a / b;
				p = 1;
			}
			else if (p) printf("0");
		}
	if (m) printf("1");
	else printf("0");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值