2022蓝桥杯c++B组,解题记录

选择题略过

本题解皆为现场题解记录,不能保证与官方题解相同。

C:刷题统计

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 a 道题目,周六和周日每天做 b 道题目。请你帮小明计算,按照计划他将在 第几天实现做题数大于等于 n 题?

当数据量较大时一天天的模拟明显速度不足,原因在于其中包含的无效计算。

如果1000天之后实现,那么是很多星期之后,而每个星期的做题量是相同的,因此这就是重复计算。所以我们采取的方法是用总题数除以每星期可以做的题目,得到需要几星期。然后余数再用模拟法判断需要几天,然后用星期*7再加上余数求出来的天数,得到总天数。

#include<iostream> 
using namespace std;
int getDayNum(int tNum,int dayNum,int a,int b,int n)
{
	for(int i=1;i<=7;i++)
	{
		if(i>=1&&i<=5)
		{
			tNum+=a;
			dayNum++;
			if(tNum>=n){
				break;	
			} 
		}
		if(i>=6)
		{
			tNum+=b;
			dayNum++;
			if(tNum>=n){
				break;	
			} 
		}
	}
	return dayNum;
}
int main()
{
	int a,b,n;
	cin>>a>>b>>n;
	bool flag=true;
	int tNum=0;
	int dayNum=0;
	while(flag)
	{
		tNum+=a*5;
		tNum+=b*2;
		dayNum+=7;
		if(tNum>=n)
		{
			flag=false;
			tNum-=a*5;
			tNum-=b*2;
			dayNum-=7;
			dayNum=getDayNum(tNum,dayNum,a,b,n);
			flag=false;
		}
	}
	cout<<dayNum;
	return 0;
}

D:修剪灌木

爱丽丝要完成一项修剪灌木的工作。 有 N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌 木,让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后,她会调转方向,下一天开 始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。 灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。在第一天的 早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

看到题目问最高长多高,就要去思考什么时候长到最高,而不是直接模拟。要针对问题找到方案,而不是模拟好约束条件之后暴力枚举。

在最左边的长的最高就是一个来回的时候长的最高,右边的就是从右边开始一个来回的时候长的最高,从中间分开,靠左的就是向右再回来一个来回的时候长的最高,靠右的同理,自己画图感受一下,我懒QWQ。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
	int n;
	cin>>n;
	if(n==0) cout<<0; 
	for(int i=1;i<=n;i++)
	{
		if(n==1)
		{
			cout<<1;
			break;
		}
		int temNum=max(n-i,i-1);
		cout<<temNum*2<<endl;
	}
	return 0;
} 

E:X 进制减法

进制规定了数字在数位上逢几进一。 X 进制是一种很神奇的进制,因为其每一数位的进制并不固定!例如说某 种 X 进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制,则 X 进制数 321 转换为十进制数为 65。 现在有两个 X 进制表示的整数 A 和 B,但是其具体每一数位的进制还不确 定,只知道 A 和 B 是同一进制规则,且每一数位最高为 N 进制,最低为二进 制。请你算出 A − B 的结果最小可能是多少。 请注意,你需要保证 A 和 B 在 X 进制下都是合法的,即每一数位上的数 字要小于其进制。

请参考我的b站视频:里面讲到进制的本质。蓝桥杯·寒假百校真题大联赛(大学B组)(第2期)题目讲解《年号字串》_哔哩哔哩_bilibili

简单的说进制的本质就是一个高位代表多少个低位,所以8进制10进制2进制

321

1是二进制,代表两个本位代表一个高位,所以1

2是10进制,是前一位进位来的,所以这一位的1代表一个2

3是8进制,是前一位进位来的,所以这一位1代表一个10

所以是3代表:3*10*2=60

2代表:2*2=4

1代表:1*1=1

总和:60+4+1=65

将上述过程固化为代码即可:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long long getNum(int *w,int *a,int ma) 
{
	long long returnNum=0;
	long long nowWeiNum=1;
	for(int i=0;i<ma;i++)
	{
		returnNum+=a[i]*nowWeiNum;
		if(returnNum>100000000000000000) returnNum%=1000000007; 
		nowWeiNum*=w[i];
		if(nowWeiNum>100000000000000000) break;
	}
	return returnNum;
}
int main()
{
	int n,ma,mb;
	cin>>n;
	cin>>ma;
	int a[ma];
	for(int i=ma-1;i>=0;i--)
	{
		cin>>a[i];
	}
	cin>>mb;
	int b[mb];
	for(int i=mb-1;i>=0;i--)
	{
		cin>>b[i];
	}
	int maxLength=max(ma,mb);
	int w[maxLength];
	for(int i=0;i<maxLength;i++)
	{
		int numa,numb;
		if(i>ma-1) numa=0;
		else numa=a[i];
		if(i>mb-1) numb=0;
		else numb=b[i];
		int wei=max(numb,numa);
		wei+=1;
		if(wei<2)wei=2;
		w[i]=wei;
	}
	long long ansA,ansB;
	ansA=getNum(w,a,ma);
	ansB=getNum(w,b,mb);
	cout<<(ansA-ansB)%1000000007;
	return 0;
} 
//可以用数学方法进一步的验证 

因为时间不够,所以就懒得处理数据溢出问题的数学解决方法,我刷题少(个位数)考试时没想到什么方法,直接限制数据大小了。

F:统计子矩阵

给定一个 N × M 的矩阵 A,请你统计有多少个子矩阵 (最小 1 × 1,最大 N × M) 满足子矩阵中所有数的和不超过给定的整数 K

因为频繁用到矩阵的大小,所以第一个优化就是创建DP表,用差分的方式直接计算某个范围内的数的和。然后我估计着之后直接遍历所有大小的矩阵就行。

#include<iostream>
using namespace std;
int mp[1000][1000];
long long dis[1000][1000]; 
int main()
{
	int ans=0;
	int n,m,k;
	cin>>n>>m>>k;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			cin>>mp[i][j];
		}
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(i-1<0&&j-1>=0) dis[i][j]=dis[i][j-1]+mp[i][j];
			else if(i-1>=0&&j-1<0) dis[i][j]=dis[i-1][j]+mp[i][j];
			else if(i-1<0&&j-1<0) dis[i][j]=mp[i][j];
			else dis[i][j]=dis[i-1][j]+dis[i][j-1]-dis[i-1][j-1]+mp[i][j];
		}
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			for(int fi=0;fi<n;fi++)
			{
				for(int fj=0;fj<m;fj++)
				{
					if(i+fi>=n||j+fj>=m) continue;
					long long num;
					if(i-1<0&&j-1>=0)
					{
						num=dis[i+fi][j+fj]-dis[i+fi][j-1];
					}
					else if(i-1>=0&&j-1<0)
					{
						num=dis[i+fi][j+fj]-dis[i-1][j+fj];
					}
					else if(i-1<0&&j-1<0)
					{
						num=dis[i+fi][j+fj];
					}
					else
					{
						num=dis[i+fi][j+fj]-dis[i-1][j+fj]-dis[i+fi][j-1]+dis[i-1][j-1];
					}
					if(num<=k) ans++;
				}
			}
		}
	}
	cout<<ans; 
	return 0;
 } 

G:积木画

小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 2 个单位面积)和 L 型(大小为 3 个单位面积): 同时,小明有一块面积大小为 2 × N 的画布,画布由 2 × N 个 1 × 1 区域构 成。小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式? 积木可以任意旋转,且画布的方向固定。

时间不做,代码我估计写起来应该涉及不少细节,所以跳过。只用排列组合计算了方形画布时的组合数。

#include<iostream>
using namespace std;
int main()
{
	long long  n;
	cin>>n;
	//if(n%6==0)
	if(n==3) cout<<5;
	else
	{
		long long block=n/6;
		long long ans=1;
		for(int i=1;i<=block;i++)
		{
			ans*=i;
		}
		ans*=600;
		cout<<ans%1000000007;
	}
	return 0;
}

H:扫雷

小明最近迷上了一款名为《扫雷》的游戏。其中有一个关卡的任务如下, 在一个二维平面上放置着 n 个炸雷,第 i 个炸雷 (xi , yi ,ri) 表示在坐标 (xi , yi) 处 存在一个炸雷,它的爆炸范围是以半径为 ri 的一个圆。 为了顺利通过这片土地,需要玩家进行排雷。玩家可以发射 m 个排雷火 箭,小明已经规划好了每个排雷火箭的发射方向,第 j 个排雷火箭 (xj , yj ,rj) 表 示这个排雷火箭将会在 (xj , yj) 处爆炸,它的爆炸范围是以半径为 rj 的一个圆, 在其爆炸范围内的炸雷会被引爆。同时,当炸雷被引爆时,在其爆炸范围内的 炸雷也会被引爆。现在小明想知道他这次共引爆了几颗炸雷? 你可以把炸雷和排雷火箭都视为平面上的一个点。一个点处可以存在多个 炸雷和排雷火箭。当炸雷位于爆炸范围的边界上时也会被引爆。

遍历导弹,每有一个导弹就引爆周围的炸弹(通过对炸弹排序可以省去无效计算),炸弹爆炸放入集合,检测爆炸范围内的炸弹,如果不在集合中说明还没爆炸,加入队列。直到队列为空,计算完成这枚导弹可以炸到的全部区域。通过并查集来加速集合元素的判断。

还没测试就交卷了,为了保证一定的正确性,就不发代码了。

后面几道题没做。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值