23-24C++(44)——使用标记变量记录状态***********

一、标记变量

标记变量不是一种变量类型,而是一种用途。

标记变量用于记录一件事是否发生过(bool 类型),

有时候也用于记录一件事发生的次数(int 类型)。

标记变量还可以不仅仅记录一件事的状态,还可以分别记录多件事的状态(数组)。

1、标记变量记录一件事的发生次数(int 类型)

【例 1】输入一个整数 a,求 a 的因数个数

#include<iostream>
using namespace std;
int main()
{
	int a, cnt = 0;
	cin >> a;
	for (int i = 1; i <= a; i++)
	{
		if (a % i == 0)
		{
			cnt++;
		}
	}
	cout << cnt;
	return 0;
}

例题中,cnt 变量起到了标记作用,用于标记有多少个 a 的因数。 在遇到 a 很大时,代码的效率很低。

应当考虑只循环到 sqrt(a),每看到一个因数 i,那么必 然还有一个因数是 a/i,故 cnt 每次加 2。

但这样做会有个 bug,比如 9,当 i 循环到 3 时,i 和 a/i 是同一个数字 3,cnt 如果还加 2, 那么就多加了 1 次。

解决方法:

   

   上述错误只有当 a 是完全平方数时才会出现,如果 a 是完全平方数,那么 cnt 最 后减 1 即可。

关于判断 a 是完全平方数,可以先令 int b=sqrt(a),如果 b 的平方是 a,说明 sqrt(a)的值是 整数,也就是说 a 是完全平方数。

例如

a=25,那么 b=sqrt(a)=5,5 的平方是 25,所以 25 是完全平方数;

如果

a=24,那么 b=sqrt(a)=4,4 的平方不是 24,所以 24 不是完全平方数。

优化后的代码:

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
	int a, cnt = 0;
	cin >> a;
	for (int i = 1; i <= sqrt(a); i++)
	{
		if (a % i == 0)
		{
			cnt += 2;
		}
	}
	int b = (int)sqrt(a);
	if (b * b == a)
	{
		cnt--;
	}
	cout << cnt;
	return 0;
}

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

2、标记变量记录一件事/多件事是否发生过(bool 类型/bool 数组)

【例 2】输入一个正整数 a,如果 a 各个位置上的数字包含了 1、2、3、4、5 这 5 个数字, 那么输出 Yes,否则输出 No。

例如,当 a=39501452 时,输出 Yes;当 a=4321 时,输出 No。

#include<iostream>
using namespace std;
int main()
{
	int a;
	cin >> a;
	bool b[6];
	for (int i = 1; i <= 5; i++)
	{b[i] = false;}
	while (a > 0)
	{
		int c = a % 10;
		if (c >= 1 && c <= 5){b[c] = true;}
		a = a / 10;
	}
	bool f = true;
	for (int i = 1; i <= 5; i++)
	{
		if (b[i] == false)
		{
			f = false;
			break;
		}
	}
	if (f){cout << "Yes";}
	else{cout << "No";}
	return 0;
}

运行结果如下——

例题中,b 数组元素 b[1]~b[5]分别记录数字 1~数字 5 是否出现过,如果没出现过,值为 false,如果出现过,值为 true。

f 变量用于记录是否有某个 b 数组的元素值为 false,

f 初值 为 true,如果看到 b 数组某个元素为 false,则改为 false。

最终,根据 f 的值可以确定输出 Yes 还是 No。

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

3、使用整型计数器记录循环周期

【例 3】有一个数列,第一项是 a,之后每一项都是

(上一项*b+c)%d

求第 n 项是多少?

(a、 b、c、d 均为不大于 100 的非负整数,n 不大于 10 亿)

#include<iostream>
using namespace std;
int main()
{
	int a, b, c, d, n, cnt = 1;
	cin >> a >> b >> c >> d >> n;
	int stat[100] = { 0 };
	while (stat[a] == 0)
	{
		stat[a] = cnt;
		cnt++;
		a = (a * b + c) % d;
	}
//说明从第 1 项到
//第 stat[a]-1 项是前导的不循环部分
//从第 stat[a]项到
//第 cnt-1 项是一个完整的循环节
if (n >= stat[a])
{//计算第 n 项相当于第几项
	n = (n - stat[a]) % (cnt - stat[a]) + stat[a];
}
for (int i = 0; i < d; i++)
{
	if (stat[i] == n)
	{
		cout << i;
		break;
	}
}
return 0;
}

4、使用二进制位记录多件事是否发生过        这题没懂

【例 3】输入 m 个整数(m<=1e+6),问 0 到 9999 之间有多少个数字至少出现过一次。(假 设这题限制内存)

说明:使用一个二进制位记录范围内的某个数字是否出现过。那么这 10000 个数字只需要 10000 位,即 1250 字节的空间就可以记录状态。数字 a 的状态记录在第 a/8 个字节的第 a%8 个二进制位上。

#include<iostream>
using namespace std;
typedef unsigned char BYTE;
void setStat(BYTE stat[], int a)//对应二进制位置 1
{
	int b = a / 8, c = a % 8;
	stat[b] = stat[b] | (1 << c);
}
int getCnt(BYTE stat[])
{
	int cnt = 0;
	for (int i = 0; i < 1250; i++)
	{
//计算 stat[i]这个字节(8 个二进制位)有多少个 1
		for (int j = 0; j < 8; j++)
		{
			if (stat[i] & (1 << j))
			{
				cnt++;
			}
		}
	}
	return cnt;
}
int main()
{
	BYTE stat[1250] = { 0 };
	int m, a;
	cin >> m;
	for (int i = 0; i < m; i++)
	{
		cin >> a;
		if (a >= 0 && a <= 9999)
		{
			setStat(stat, a);
		}
	}
	cout << getCnt(stat);
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拔刀能留住落樱吗、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值