每日一题:好数【蓝桥杯 2024 省 B】

目录

一、题目

二、更多示例

三、解题思路


一、题目

二、更多示例

1、输入4048     输出275.

2、输入5821     输出400.

3、输入10000000      输出94400.

三、解题思路

1、构成好数的条件:一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位……)上的数字是奇数,偶数位(十位、千位、十万位……)上的数字是偶数。

这意味着我们要去判断一个数的每一位,当奇数位的数字为奇数,偶数位时为偶数时,这个数就为好数。那我们怎么去判断呢?同时我们也要去看全部测试数据也即N的范围,以防N大于整型的存储范围(-2147483648 到 2147483647),1<=N<=10的7次方,因此N的大小未超范围,不用对N做出改变。

2、我们知道只要一个数对10进行取余操作,就可以获得这个数的最后一位。

int main()
{
	int a = 2024;
	int b = a % 10;
	printf("%d", b);
	return 0;
}

结果为4.

这时如果我们可以将这个数的最后一位去掉,然后继续进行取余操作,不就可以获得下一位的数字。恰好a=a/10;可以将最后一位去掉。而如果我们将上述操作放入循环中,我们就可以得到这个数的每一位。由此我们可以得到以下代码:

int main()
{
	int n;
	scanf("%d", &n);
	int j = 1, b = 0;
	while (n)
	{
		//b用来储存这个数的每一位
		b = n % 10;
		//j用来记录循环次数,也即j-1为这个数的位数。之所以令j=1,是为了对应这个数的奇数位和偶数位,为后续判断提供便利
		j++;
		//去除这个数的最后一位,当这个数只有一位时n=0,循环停止
		n = n / 10;
	}
	return 0;
}

当我们可以得到这个数的每一位时,我们就可以对它的每一位进行判断,代码如下:

int main()
{
	int n;
	scanf("%d", &n);
	int j = 1, b = 0,a=0,c=0;
	while (n)
	{
		//b用来储存这个数的每一位
		b = n % 10;
		//判断这个数的奇数位是奇数偶数位是偶数,如果不是,则令a的值位1。
		if ((j % 2 == 0 && b % 2 != 0) || (j % 2 == 1 && b % 2 != 1))
		{
			a=1;
		}
		//j用来记录循环次数,也即j-1为这个数的位数。之所以令j=1,是为了对应这个数的奇数位和偶数位,为后续判断提供便利
		j++;
		//去除这个数的最后一位,当这个数只有一位时n=0,循环停止
		n = n / 10;
	}
	//记录达成好数条件的数的个数
	if (a == 0)
	{
		c++;
	}
	return 0;
}

如果我们需要获得1~N内好数的个数,我们只需要在外加入一个循环即可。代码如下:

#include<stdio.h> 
int main()
{
	int N;
	scanf("%d",&N);
	int c=0;
	for (int i = 1; i <= N; i++)
	{
		//令n=i是因为在后续操作中会改变n的值,从而死循环,所以不直接使i作为while循环的值 
		int j = 1,b=0,n=i,a=0;
		while (n)
		{
			//b用来储存这个数的每一位
			b = n % 10;
			//判断这个数的奇数位是奇数偶数位是偶数,如果不是,则令a的值位1。
			if ((j % 2 == 0 && b % 2 != 0) || (j % 2 == 1 && b % 2 != 1))
			{
				a = 1;
				break;
			}
			//j用来记录循环次数,也即j-1为这个数的位数。之所以令j=1,是为了对应这个数的奇数位和偶数位,为后续判断提供便利
			j++;
			//去除这个数的最后一位,当这个数只有一位时n=0,循环停止
			n = n / 10;
		}
		//记录达成好数条件的数的个数
		if (a == 0)
		{
			c++;
		}
	}
	//打印1-N的好数个数。
	printf("%d", c);
	return 0;
}

如此即可解决题目,我们也可以将内循环放入一个函数中,以使代码更好理解,美观。代码如下:

#include<stdio.h>
int css(int n)
{
	int j=1,b=0;
	while(n)
	{
		b=n%10;
		if((j%2==0 && b%2!=0) || (j%2==1 && b%2!=1))
		{
			return 0;
		}
		j++;
		n=n/10;
	}
	return 1;
}
int main()
{
	int N,a=0;
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
	{
		a+=css(i);
	}
	printf("%d",a);
	return 0;
} 

### 蓝桥杯 2021 赛 B组 最少刷题 C++ 解法 #### 题目解析 此问题的核心在于模拟小明每日刷题的过程并判断在哪一天累计完成的题目量达到或超过目标值 \(n\)。通过分析每周的工作模式,可以得出以下结论: - **工作日(周一到周五)**:每天完成 \(a\) 道题目。 - **周末(周六和周日)**:每天完成 \(b\) 道题目。 为了高效解决该问题,可以通过分阶段累加的方式逐步逼近目标值 \(n\),直到满足条件为止[^2]。 --- #### 实现思路 1. 定义变量存储当前已完成的总题目 `total` 和已过去的天 `days`。 2. 使用循环逐天增加题目,并更新 `total` 和 `days` 的值。 3. 当前一周结束时(即经过了 7 天),重新开始新的一周。 4. 循环终止条件为 `total >= n`。 5. 返回最终所需的天 `days`。 以下是基于上述逻辑的 C++ 实现代码: ```cpp #include <iostream> using namespace std; int main() { long long a, b, n; cin >> a >> b >> n; long long total = 0; // 已完成的题目 int days = 0; // 过去的天 while (true) { // 周一至周五 for (int i = 0; i < 5 && total < n; ++i) { total += a; days++; if (total >= n) break; } if (total >= n) break; // 周六和周日 for (int i = 0; i < 2 && total < n; ++i) { total += b; days++; if (total >= n) break; } if (total >= n) break; } cout << days; return 0; } ``` --- #### 关键点说明 1. **据范围处理** 根据题目描述中的约束条件 \(1 \leq a, b, n \leq 10^{18}\),需使用 `long long` 类型来防止溢出。 2. **效率优化** 如果直接按天逐一累加可能会导致性能瓶颈,因此可以在每次完整的一周结束后快速跳过多个周期,减少不必要的迭代次[^3]。 --- #### 测试用例验证 对于给定样例输入: ``` 10 20 99 ``` 程序运行过程如下: - 第 1 至第 5 天:\(10 \times 5 = 50\), 总计 50 题; - 第 6 天(周六):\(50 + 20 = 70\); - 第 7 天(周日):\(70 + 20 = 90\); - 第 8 天(下周一):\(90 + 10 = 100\) (满足条件)。 输出结果为: ``` 8 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值