Codecraft-18 and Codeforces Round #458(C)-Travelling Salesman and Special Numbers(数位DP)

本文介绍了一道关于寻找特殊数的算法题目。特殊数是指通过特定操作最少需要k步能减少至1的正整数。文章详细解释了操作规则及求解思路,采用数位动态规划方法,并给出完整代码实现。
C. Travelling Salesman and Special Numbers
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

The Travelling Salesman spends a lot of time travelling so he tends to get bored. To pass time, he likes to perform operations on numbers. One such operation is to take a positive integer x and reduce it to the number of bits set to 1 in the binary representation of x. For example for number 13 it's true that 1310 = 11012, so it has 3 bits set and 13 will be reduced to 3 in one operation.

He calls a number special if the minimum number of operations to reduce it to 1 is k.

He wants to find out how many special numbers exist which are not greater than n. Please help the Travelling Salesman, as he is about to reach his destination!

Since the answer can be large, output it modulo 109 + 7.

Input

The first line contains integer n (1 ≤ n < 21000).

The second line contains integer k (0 ≤ k ≤ 1000).

Note that n is given in its binary representation without any leading zeros.

Output

Output a single integer — the number of special numbers not greater than n, modulo 109 + 7.

Examples
input
110
2
output
3
input
111111011
2
output
169
Note

In the first sample, the three special numbers are 35 and 6. They get reduced to 2 in one operation (since there are two set bits in each of35 and 6) and then to 1 in one more operation (since there is only one set bit in 2).

题意:给你一个n,然后问你1到n中有多少个数按照题意操作k次正好编变成1

操作规则:对于当前数,将其转化为二进制看有多少个1,则该数变成1的个数之和,算操作一次。

题解:n有2的1000次方这么大,但是我们知道在第一次操作后一定变成了一个1000以内的数,因此我们可以预处理出来前1000个数变成1要操作多少次,然后对n的二进制表示进行数位dp即可。设dp[x][y]:二进制表示为x位,1的个数为y以内满足题目的个数。

#include<stdio.h>
#include<string.h>
#define mod 1000000007
char s[1005];
int f[1005],digit[1005],dp[1005][1005],k,len;
void init()
{
	memset(dp,-1,sizeof(dp));
	for(int i=2;i<=1000;i++)
	{
		int tmp=i,num=0;
		while(tmp)
			num+=tmp%2,tmp/=2;
		f[i]=f[num]+1;
	}
}
int dfs(int pos,int num,int lim)
{
	if(pos==0) return (f[num]==k-1);
	if(!lim && dp[pos][num]!=-1) 
		return dp[pos][num];
	int res=0,sum=lim?digit[pos]:1;
	for(int i=0;i<=sum;i++)
	{
		int tmp=num;
		if(i>0) tmp++;
		res+=dfs(pos-1,tmp,lim && i==sum);
		res%=mod;
	}
	return lim?res:dp[pos][num]=res;
}
int main(void)
{
	init();
	scanf("%s%d",s+1,&k);
	int len=strlen(s+1);
	for(int i=1;i<=len;i++)
		digit[i]=s[i]-'0';
	int l=1,r=len;
	while(l<=r)
	{
		int tmp=digit[l];
		digit[l]=digit[r];
		digit[r]=tmp;
		l++;r--;
	}
	if(k==0)
	{
		printf("1\n");
		return 0;
	}
	if(k==1)
	{
		printf("%d\n",len-1);
		return 0;
	}
	printf("%d\n",dfs(len,0,1));
	return 0;
}




源码链接: https://pan.quark.cn/s/a4b39357ea24 Modbus协议是一种普遍应用的通信协议,在工业自动化领域具有显著地位,它为不同设备间的客户机/服务器通信确立了标准。该协议立足于OSI模型的第7层,即应用层,旨在实现通过多种总线或网络连接的设备之间的数据交换。Modbus协议主要由三个核心部分构成: 1. **Modbus协议规范**:这部分详细阐述了MODBUS事务处理机制,包括如何组织和发送请求/响应报文。它定义了一组功能码,这些功能码是MODBUS协议的数据包(PDU)的组成部分,用于表明不同的服务操作。 2. **MODBUS报文传输在TCP/IP上的实现指南**:这一部分为开发者提供了在TCP/IP上实现MODBUS应用层的指导,参考了IETF的标准RFC793(TCP)和RFC791(IP),以确保MODBUS报文能在网络上正确传输。 3. **MODBUS报文传输在串行链路上的实现指南**:针对使用如EIA-232和EIA-485等串行通信标准的设备,提供了实现MODBUS应用层的指导,确保在串行链路上的数据完整性。 MODBUS协议支持两种通信模式: - **Modbus RTU (Remote Terminal Unit)**:适用于异步串行通信,通常用于低速、短距离通信,如EIA/TIA-232、EIA-422和EIA/TIA-485。 - **Modbus TCP/IP**:基于互联网协议,使用以太网II/802.3标准,适合高速、远程通信。 在MODBUS通信栈中,MODBUS应用层位于TCP/IP之上,借助TCP的可靠连接特性,确保数据包按顺序到达。而在串行链路上,MODBUS协议则直接与物理层交...
源码直接下载地址: https://pan.quark.cn/s/31ad939aed54 "关于 SR 锁存器的解析及其应用" SR 锁存器被视为一种核心的数字电子技术部件,它在数字电路构建和计算机系统的开发中占据着举足轻重的地位。SR 锁存器的构造基础是两个与非门,具体标识为 G1 和 G2。该锁存器的工作机制主要依托于 S 和 R 两个输入端信号的逻辑关联,以此来调控输出端 Q 的状态。 SR 锁存器的工作机制可以依据输入信号的不同组合分为四种情形: 1. 在 R=0、S=0 的条件下,状态将保持恒定,即 Qn+1 等同于 Qn。 2. 当 R=0、S=1 时,执行置位操作,使得 Qn+1=1。 3. 若 R=1、S=0,则执行复位操作,导致 Qn+1=0。 4. 当 R=1、S=1 时,状态呈现不确定特性,输出端 Q 的具体状态无法预测。 SR 锁存器的实践应用极为普遍,譬如在数字电路的规划中,它能够充当 Flip-Flop 功能的载体,常见于计数器、寄存器以及计算机系统之中。此外,SR 锁存器也被广泛用于消弭由机械开关触点颤动所引发的脉冲信号输出问题。 逻辑门控 SR 锁存器可视为 SR 锁存器的一种演进形态,它通过增设使能信号 E,对 SR 锁存器的输出进行调控。逻辑门控 SR 锁存器的运作机制基于 E、S 以及 R 三个输入端信号的逻辑联系,用以控制输出端 Q 的状态。 逻辑门控 SR 锁存器的应用场景同样十分多样,例如在数字电路的设计过程中,它能够协助实现更为复杂的逻辑操作。 D 锁存器亦是一种基础性的数字电子技术器件,其运作原理与 SR 锁存器相近,但 D 锁存器的输出端 Q 仅受输入信号 D 的影响。D 锁存器的实践用途同样广泛,例如在数字电路的...
源码直接下载地址: https://pan.quark.cn/s/96ee77ac4da8 根据题目指示,我们将从标题“C 语言 打印沙漏”、描述“PAT 测试题 打印沙漏 但是不知道为什么我的提交就是无效”以及部分提供的代码片段入手,对与“打印沙漏”相关的基础知识进行深入剖析。 ### 一、问题背景 题目要求在 C 语言环境下开发程序,用以生成一个沙漏形态。该任务属于 PAT(Programming Ability Test)考试中的一个环节,主要评估考生对循环结构的掌握和应用水平。从描述信息来看,尽管提交者已经完成了代码的编写工作,但在 PAT 平台上却显示提交无效。这或许是因为程序在逻辑上存在偏差或未能满足题目的具体规范所致。 ### 二、打印沙漏的原理 #### 1. 沙漏的基本构造 沙漏由上下两个对称部分构成。每一行均由一定数量的星号和空格组成。随着行数的改变,星号的数量也会发生相应的增减变化。 #### 2. 实现过程 - **确定沙漏的规模**:首先需要明确沙漏的总行数(n),这将直接影响沙漏的最大宽度。 - **计算每一行的星号数目**:对于第 i 行(i 从 1 开始计算),其星号数目遵循公式 `2 * (n - abs(i - n)) - 1` 进行确定。 - **确定每行的空格数目**:对于第 i 行,空格数目为 `abs(n - i) - 1`。 - **输出星号和空格**:依据计算出的数量,依次输出星号和空格即可完成一行的打印。 #### 3. 代码范例 下面给出一个基础的 C 语言代码范例,用于生成沙漏: ```c #include <stdio.h> int main() { int n; printf("请输入沙漏的行数:"); sc...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值