蓝桥杯2018第九届C语言B组省赛习题题解

习题A:第几天

在这里插入图片描述

题意解析

记得判断闰年,2020年是闰年,剩下的手算就行,直接加一下就好

习题B:明码

在这里插入图片描述

题意解析

一个字节八位,这里题目的意思就是,给你十段数字,每一段数字有32个有符号整数,0是底色,不用管,每个汉字用32个字节表示,其实说白了,就是把一行的所有字符表示成二进制,人后按照排版的方式,安排好,就可以从一堆的0和1的字符中看出一个汉字,是个汉字就可以看懂题意了,
十进制转换成八位的二进制数
如果是0,就全部为0
如果大于0,首位是0,后面就是对应的数字的二进制
如果小于0,首位是1,后面

代码展示

#include <iostream>
using namespace std;

void toBinaryStr(int i,string &ans)
{
    if(i>=0){
        ans[0] = '-';
        for(int j=0;j<7;j++)
        {
            if(((i>>j) & 1) == 1)//验证一个数的二进制数的某一位是否是1
            {
                ans[8-j-1] = '1';//其实就是在比较右移几位是1,逆序填进去
            }
        }
    }
    else
    {
        ans[0] = '1';
        for(int j=0;j<7;j++)
        {
            if((((i+128)>>j) & 1 ) == 1)//八位,负数可以直接先加上2^7,然后直接按照正数计算(-1,就相当于127)
            {
                ans[8-j-1] = '1';
            }
        }
    }
}
int main()
{
    for(int i=0;i<10;i++){
        //下面的32个数字组成一个汉字
        for(int j=0;j<16;j++)
        {
            int x,y;
            cin>>x>>y;
            string xx = "--------",yy = "--------";//优化一下,背景的0看起来模糊,换成-
            toBinaryStr(x,xx);
            toBinaryStr(y,yy);//转换成二进制字符串
            cout<<xx+yy<<endl;
        }
        cout<<endl;
        cout<<"========================="<<endl;//分隔开,为了看清
    }

    long long ans = 9;
    for(int k=0;k<9;k++)
        ans *= 9;
    cout<<ans<<endl;
    return 0;
}

/*
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0 
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16 
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0 
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4 
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64 
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128 
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0 
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0 
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0 
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0 
*/

习题C:乘积尾零

在这里插入图片描述

题意分析

这道题,只要将每个数分解成2和5相乘的式子(如 30=523),当然不能分解的就不要管他了,最后统计出有多少个2和5,输出较少的数即可。之所以酱紫是很容易理解的,两个数相乘等于这两个数分解后得到的式子相乘,然后在1-9这九个数字中,只有2和5的配合才能产生0;

代码展示

#include <iostream>
#include<cmath>

using namespace std;

int main()
{
    int data[105];
    for(int i=0;i<100;i++)
    {
        cin>>data[i];
    }
    int c2 = 0,c5 = 0;
    for(int i=0;i<100;i++)
    {
        int num = data[i];
        while(num %2 == 0){
            c2++;
            num/=2;
        }

        while(num%5==0)
        {
            c5++;
            num/=5;
        }
    }
    cout<<min(c2,c5)<<endl;
    return 0;
}

/*
5650 4542 3554 473 946 4114 3871 9073 90 4329
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899
1486 5722 3135 1170 4014 5510 5120 729 2880 9019
2049 698 4582 4346 4427 646 9742 7340 1230 7683
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649
6701 6645 1671 5978 2704 9926 295 3125 3878 6785
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074
689 5510 8243 6114 337 4096 8199 7313 3685 211
*/

习题D:测试次数

x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。

x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。

如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n

为了减少测试次数,从每个厂家抽样3部手机参加测试。

某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?

请填写这个最多测试次数。

注意:需要填写的是一个整数,不要填写任何多余内容。

思路分析

就是递推,但是不要陷入思维陷阱,最佳的策略不一定就是从中间开始噢,一定要把前几个分析一下从每一层开始,情况是好是坏分析一下,就可以得出结论。

代码展示

#include<bits/stdc++.h>
#include<climits>
using namespace std;
//忘记思路看这个https://www.bilibili.com/video/BV1aK4y1v7mE?p=18&spm_id_from=pageDriver 
const int N = 1000;
int f1[N+1],f2[N+1],f3[N+1];//记录手机数为1,2,3时,随影各层的测试次数
int main()
{
	//1部手机的情况
	for(int i=1;i<=N;i++)
	{
		f1[i] = i;
	 } 
	
	//考虑2部手机的情况
	for(int i=1;i<=N;i++){
		int ans =  INT_MAX;
		//尝试1~i若干中方案,最终记录所有方案中次数最少的
		for(int j=1;j<=i;j++)//在j层扔第一个手机
		{
			//1 好的 2 坏了 
		    int _max =1 + max(f2[i-j], f1[j-1]);
			ans = min(ans,_max); 
		 } 
		 f2[i] = ans; 
	} 
	
	//考虑三部手机的情况
	for(int i=1;i<=N;i++){
		int ans =  INT_MAX;
		//尝试1~i若干中方案,最终记录所有方案中次数最少的
		for(int j=1;j<=i;j++)//在j层扔第一个手机
		{
			//1 好的 2 坏了 
		    int _max =1 + max(f3[i-j], f2[j-1]);
			ans = min(ans,_max); 
		 } 
		 f3[i] = ans; 
	} 
	cout<<f3[N]<<endl;
	return 0;
 } 

习题F 递增三元组

在这里插入图片描述

题意分析

其实这就是以前蓝桥杯称之为暴力杯的源头,题意简单易懂,哪怕最笨的人,也可以使用简单的三重循环拿点分数,这道题目的真正得分的点在于优化,我们可以先把三个数组按照从小到大的顺序排好序,然后因为b在三个数的中间,所以考虑问题的时候,不要单一的被题目牵着鼻子走,不要先从a考虑,你先从b开始考虑,对于每一个b[i],你可以在a中找到比b[i]小的数,在c中找到比b[i]大的数,设置一个p指针在a中,设置一个q指针在c中,这样随着b数组的逐渐增大,p,和 q会按照顺序改变,也就可以避免重复的计算。在这里插入图片描述

代码展示

#include<bits/stdc++.h>
#include<climits>
#include<algorithm>
using namespace std;

int n;
long long ans;
int main()
{
	cin>>n;
	int a[n],b[n],c[n];
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	for(int i=0;i<n;i++)
	{
		cin>>b[i];
	}
	for(int i=0;i<n;i++)
	{
		cin>>c[i];
	}
	
	sort(a,a+n);//首先把他们从小到大排好序 
	sort(b,b+n);
	sort(c,c+n);
	
	int p = 0,q = 0;
	for(int i=0;i<n;i++)//以b数组的每一个数为基准,向前找a数组,向后找c数组 
	{
		while(p<n && a[p]< b[i]) p++;
		while(q<n && c[q] <= b[i]) q++;//q是比b[i]小的个数,所以才要加上=,推出比b[i]大的个数为n-q;
		ans += (long long) p*(n-q);
	}
	cout<<ans<<endl;
	return 0;
 } 

习题G:螺旋折线

在这里插入图片描述

题意分析

看到图,如果直接暴力肯定超时,并且还可能会超int,所以,参考别人的https://www.bilibili.com/video/BV1aK4y1v7mE?p=20&spm_id_from=pageDriver方法
从左上角到右下角划一道线,这样就将整个图形长度分成了两个等差数列,上边的是4,8,12,
下边的是2,6,10,这样每次都以右下角为基准,算出右下角的长度,通过计算距离最近的右下角的长度,计算出他的合理长度

代码展示

#include<bits/stdc++.h>
#include<climits>
#include<algorithm>
using namespace std;

//等差数列求和
#define sum(a0,n,d) (2*(a0) + ((n)-1)*(d))*(n)/2

typedef long long ll;

int main()
{
	ll x,y;
	cin>>x>>y;
	ll d = 0;//距离
	ll n = 0;//取第几圈
	if(y>0 && abs(x)<=y)
	{//最上方的倒三角的地方
		n = y;
		d = y - x + 2 * y;
	} 
	else if(x > 0 && abs(y) <= x)
	{//右侧的倒三角的位置
		n = x;
		d = y+x;
	}
	else if(y<=0 && x>= y-1 && x<= -y)
	{//下边的倒三角,但是是n-1行的噢,注意找到走的规律
		n = -y;
		d = -(-y-x);
	}
	else if(x <0 && y>= x+1 && y<= -x)
	{//左边的倒三角
		n = -x-1;
		d = -(y-x-1-2*x -1);
	}
	cout<<sum(1, 2*n, 1) * 2 - d<<endl;
	return 0;
 } 

习题H:日志统计

在这里插入图片描述

思路分析

代码展示

#include<bits/stdc++.h>
#include<climits>
#include<algorithm>
using namespace std;


int N,D,K;
struct R{
	int ts,td;//时刻及id 
};

bool cmp(R r1,R r2)
{//按照时刻对一个记录R做升序排序 
	return r1.ts < r2.ts;
}


void out(R r[])
{
	for(int i=0;i<N;i++)
	{
		cout<<r[i].ts<<" "<<r[i].td<<endl;
	}
}


int main()
{
	cin>>N>>D>>K;
	//存日志数据,ts-td分别是时刻及id,组合成对象,存储在vector 
	vector<R> records(N);
	map<int ,int> cnt;//记录id及其出现的次数
	//读取日志文件
	for(int i=0;i<N;i++)
	{
		cin>>records[i].ts >> records[i].td;
	} 
	 
	//用自定义比较器排序
	sort(records.begin(),records.end(),cmp);
	 
	int j = 0;//用于往后探的指针——尺取法的哨兵 
	set<int> answers;//记录结果id
	for(int i=0;i<N;i++){//i是尺取法的起点 
		while(j<N && records[j].ts - records[i].ts < D)
		{
			cnt[records[j].td]++;//该id的技术+1
			if(cnt[records[j].td] >= K)//如果计数满足条件 
				answers.insert(records[j].td);//id放入answer中 
			j++; 
		}
		cnt[records[i].td]--;//上一个 区间,td的技术要扣除,不干扰下一个区间的统计 
	}
	//输出答案 
	for(set<int>::iterator i =  answers.begin();i != answers.end();i++)
	{
		cout<<*i<<endl;
	}
	
	return 0;
}
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝桥杯是一个国内著名的计算机比赛,为了帮助参赛者更好地准备和了解比赛的题型,委会会公布历年的真题并提供相应的题解。 首先,我们需要了解蓝桥杯是一个综合性的计算机比赛,测试的对象包括计算机基础知识、编程能力以及解决实际问题的能力。 在历年的真题中,参赛者将面临不同类型的题目,包括算法设计与优化问题、数据结构与算法问题、编程题等。其中针对Python B的题目主要考察的是对Python语言的掌握和应用能力。 题目解答一般会包含以下几个方面的内容: 1. 题目分析与理解:读取题目,理解题目的要求和限制条件。通过仔细分析题目,确定题目的输入与输出,以及问题的核心。 2. 设计解决方案:根据题目要求和限制条件,设计一个合适的解决方案。可以使用合适的算法和数据结构来解决问题,并做出相应的性能优化。 3. 编写代码实现:根据设计的方案编写相应的代码实现。需要注意的是,Python语言有其独特的语法和特性,掌握好这些特性可以更好地完成编程任务。 4. 调试与测试:编写完代码后,需要进行调试和测试。通过运行样例输入和输出,检查代码是否符合题目要求,并且没有逻辑上的错误。 5. 总结与优化:在完成题目解答后,可以进行总结和优化。包括分析算法复杂度、代码风格和可读性等方面,以便在比赛中更好地表现。 在准备蓝桥杯时,可以通过阅读历年的真题和题解来了解比赛的难度和类型,针对性地进行练习和提高。同时也可以参加相关的培训班和讨论活动,与其他参赛者交流经验和技巧。 总而言之,历年蓝桥杯真题的解答对于提高自己的编程能力和应对比赛非常有帮助。通过认真分析和实践,可以更好地理解并掌握Python编程,并在比赛中取得更好的成绩。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值