Codecraft-18 and Codeforces Round #458: C. Travelling Salesman and Sp(组合数)

本文探讨了一个关于二进制数字变换的问题,输入为一个二进制数n和一个整数k,目标是计算满足特定条件的数字数量。通过预处理和数位DP等方法,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



题意:

对于数字x,令F[x] = x二进制中1的个数

输入两个数字n(输入为二进制)和k,问有多少个满足①<=n;②刚好进行k次F[]计算后变为1


思路:

显然n<=2^1000但是第一次F[]计算之后一定会变成一个<=1000的数

先预处理1到1000每个数要变几次,然后对于刚好变k-1次的数x就相当于求出有多少个数满足

①<=n;②二进制刚好有x个1

这可以用数位DP或者组合数学解决

大概就是如果当前位是1的话把它变成0后面所有数字都可以01任选了,具体看代码

最后对于每个合法的x算出来的情况数全部加在一起就是答案

不过这样有两个坑,一个是k=0是答案一定为1,第二个是k=1时注意计算出的答案要-1

#include<stdio.h>
#include<string.h>
#define LL long long
#define mod 1000000007
int a[1005];
LL C[1005][1005];
char str[1005];
int Jud(int x)
{
	int now, sum = 0;
	while(x>1)
	{
		sum++;
		now = 0;
		while(x)
		{
			if(x%2==1)
				now++;
			x /= 2;
		}
		x = now;
	}
	return sum;
}
LL Sech(int x)
{
	LL sum = 0;
	int i, n, cnt = 0;
	n = strlen(str+1);
	for(i=1;i<=n;i++)
	{
		if(str[i]=='1')
		{
			if(cnt<=x)
				sum = (sum+C[n-i][x-cnt])%mod;
			cnt++;
		}
	}
	if(cnt==x)
		sum = (sum+1)%mod;
	return sum;
}
int main(void)
{
	LL ans;
	int i, j, k;
	for(i=1;i<=1000;i++)
		a[i] = Jud(i);
	C[0][0] = 1;
	for(i=1;i<=1000;i++)
	{
		C[i][0] = 1;
		for(j=1;j<=i;j++)
			C[i][j] = (C[i-1][j-1]+C[i-1][j])%mod;
	}
	scanf("%s%d", str+1, &k);
	if(k==0)
	{
		printf("1\n");
		return 0;
	}
	ans = 0;
	for(i=1;i<=1000;i++)
	{
		if(a[i]==k-1)
			ans = (ans+Sech(i))%mod;
	}
	if(k==1)
		ans--;
	printf("%I64d\n", ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值