【2023蓝桥杯】2018年第九届C/C++A组真题(解析笔记)

目录

【分数】循环累乘/快速幂运算/最大公因数

【星期一】闰年/周期循环

【乘积尾零】遍历/取余/取整

【第几个幸运数】 遍历

【打印图形】dfs填空

×【航班时间】字符串/思维/时间换算

×【三体攻击】差分!中等难度

【全球变暖】dfs/连通块+计数

*【倍数问题】暴力/数论/构造

×【付账问题】贪心


【分数】循环累乘/快速幂运算/最大公因数

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

1+1/2+1/4+1/8+⋯

每项是前一项的一半,如果一共有 2020 项,求这个和是多少,结果用分数表示出来。

类似:3/2,当然,这只是加了前 2项而已。分子分母要求互质。

考点:循环累乘/快速幂运算

int gcd=__gcd(a,sum);    //求最大公因数 

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

int main(){
	int a=1;
	int sum=0;
	for(int i=1; i<=2020; i++){
		sum=sum+a;		//分子 
		a=a*2; 			//更新a,最终为分母 		
	}
	int gcd=__gcd(a,sum);	//求最大公因数 
	a = a/gcd; 				//除法
	sum = sum/gcd; 
	printf("%d/%d",sum,a/2);
}

【星期一】闰年/周期循环

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

整个 2020 世纪(1901 年 1 月 1 日至 2000年12 月 31 日之间),一共有多少个星期一?)5217

考点:闰年/周期循环

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

//判断闰年
bool isleap(int x){
	return x%400==0||(x%4==0&&x%100!=0);
} 
int main(){
	int t=0;
	//计算总天数 
	for(int i=1901; i<=2000; i++){
		if(isleap(i))
		 t+=366;
		else t+=365;
	}
	//查日历已知2000年12月31日
	//扣除26日至31日的6天 
	t-=6; 
	int res=0;
	//从周一开始计数 
	for(int i=t; i>0; i-=7){
		res++;
	} 
	cout<<res<<endl;
}

【乘积尾零】遍历/取余/取整

乘积尾零 - 蓝桥云课 (lanqiao.cn)

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

如下的 1010 行数据,每行有 10个整数,请你求出它们的乘积的末尾有多少个零?

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 

方法1:遍历/取余/取整

方法2:先找出多少个能相乘等于零;计算出里面有多少个数是包含5和2;然后比较找出有多少个可以5和2可以相乘等于零;然后输出

#include<bits/stdc++.h>
using namespace std;
long long a[10][10]; 

int main(){
	//读取数据 
	for(int i=1;i<=10;i++){
		for(int j=1; j<=10; j++){
			cin>>a[i][j];
		}
	}
	//计算乘积
	int count=0;
	long long res=1; 
	long long x=1000000000;
	for(int i=1;i<=10;i++){
		for(int j=1; j<=10; j++){
			//cout<<a[i][j]<<endl;
			res=res*a[i][j];
			//末尾为0计数 
			while(res%10==0){
				res/=10;
				count++; 
			} 
			res=res%x;
		}
	}
	cout<<count<<endl;
}
#include <iostream>
using namespace std;
int cnt2,cnt5;
int a[100];

int main(){
  for(int i=0;i<=99;i++){
   cin>>a[i];
    while(a[i]%2==0){
      cnt2++;
      a[i]/=2;
    }
    while(a[i]%5==0){
      cnt5++;
      a[i]/=5;
    }
  }
  cout << min(cnt2,cnt5) << endl;
  return 0;
}

【第几个幸运数】 遍历

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

到 X 星球旅行的游客都被发给一个整数,作为游客编号。

X 星的国王有个怪癖,他只喜欢数字 3,5 和7。

国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。

我们来看前 10 个幸运数字是:3,5,7,9,15,21,25,27,35,45因而第 11 个幸运数字是: 49
小明领到了一个幸运数字 59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。

请你帮小明计算一下,59084709587505是第几个幸运数字。 1905

方案:遍历

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

int main(){
  //目标 n = a*b*c
  //a,b,c为3,5,7的倍数
  long long n = 59084709587505;
  int ans=0;
  for(long long i=1; i<=n; i*=3){
     for(long long j=1; i*j<=n; j*=5){
       for(long long k=1; k*i*j<=n; k*=7){
          ans++;
       }
     }
  }
  //排除1*1*1情况
  cout << ans - 1;
  return 0;
}

【打印图形】dfs填空

本题为代码补全填空题,请将题目中给出的源代码补全,并复制到右侧代码框中,选择对应的编译语言(C/Java)后进行提交。若题目中给出的源代码语言不唯一,则只需选择其一进行补全提交即可。复制后需将源代码中填空部分的下划线删掉,填上你的答案。提交后若未能通过,除考虑填空部分出错外,还需注意是否因在复制后有改动非填空部分产生错误。

如下的程序会在控制台绘制分形图(就是整体与局部自相似的图形)。

当 n=1,2,3 的时候,输出如下: 请仔细分析程序,并填写划线部分缺少的代码。

n=1 时:

 o 
ooo
 o 

 n=2 时:

    o    
   ooo   
    o    
 o  o  o 
ooooooooo
 o  o  o 
    o    
   ooo   
    o    

n=3 时 :

             o             
            ooo            
             o             
          o  o  o          
         ooooooooo         
          o  o  o          
             o             
            ooo            
             o             
    o        o        o    
   ooo      ooo      ooo   
    o        o        o    
 o  o  o  o  o  o  o  o  o 
ooooooooooooooooooooooooooo
 o  o  o  o  o  o  o  o  o 
    o        o        o    
   ooo      ooo      ooo   
    o        o        o    
             o             
            ooo            
             o             
          o  o  o          
         ooooooooo         
          o  o  o          
             o             
            ooo            
             o             

方法: 图像类似向外扩张,优先随机设数,查看基础实现效果,dfs填空

#include <stdio.h>
#include <stdlib.h>

void show(char* buf, int w){
    int i,j;
    for(i=0; i<w; i++){
        for(j=0; j<w; j++){
            printf("%c", buf[i*w+j]==0? ' ' : 'o');
        }
        printf("\n");
    }
}

void draw(char* buf, int w, int x, int y, int size){
    if(size==1){
        buf[y*w+x] = 1;
        return;
    }
    
    //int n = _________________________ ; //填空
    //int n = 1 ; //尝试效果 n=1 成立 
	int n = size/3 ; 
    draw(buf, w, x, y, n);
    draw(buf, w, x-n, y ,n);
    draw(buf, w, x+n, y ,n);
    draw(buf, w, x, y-n ,n);
    draw(buf, w, x, y+n ,n);
}

int main()
{
    int N ;
        scanf("%d",&N);
    int t = 1;
    int i;
    for(i=0; i<N; i++) t *= 3;
    
    char* buf = (char*)malloc(t*t);
    for(i=0; i<t*t; i++) buf[i] = 0;
    
    draw(buf, t, t/2, t/2, t);
    show(buf, t);
    free(buf);
    
    return 0;
}

【航班时间】字符串/思维/时间换算

航班时间 - 蓝桥云课 (lanqiao.cn)

小 h 前往美国参加了蓝桥杯国际赛。小 h 的女朋友发现小 h 上午十点出发,上午十二点到达美国,于是感叹到"现在飞机飞得真快,两小时就能到美国了"。

小 h 对超音速飞行感到十分恐惧。仔细观察后发现飞机的起降时间都是当地时间。由于北京和美国东部有 12 小时时差,故飞机总共需要 14 小时的飞行时间。 

不久后小 h 的女朋友去中东交换。小 h 并不知道中东与北京的时差。但是小 h 得到了女朋友来回航班的起降时间。小 h 想知道女朋友的航班飞行时间是多少。

对于一个可能跨时区的航班,给定来回程的起降时间。假设飞机来回飞行时间相同,求飞机的飞行时间。

方法:数学思维/思维/时间换算

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

const int day = 24*60*60;    //全部转化为秒 
const int hour = 60*60;
const int minutes = 60;
 
int start() {      //出发时间 
    int a,b,c;
    scanf("%d:%d:%d",&a,&b,&c);
    int time = a*hour + b*minutes + c;
    return time;
}
 
int end() {   //到达时间 
    int a,b,c;
    scanf("%d:%d:%d",&a,&b,&c);
    int time = a*hour + b*minutes + c;
    char ch,extra_day;
    while( (ch = getchar())!='\n' && ch != '\r' ) {
        if(ch == '(') {
            getchar();  //除去"+" 
            extra_day = getchar();   //额外天数 
            time = time + (extra_day - '0')*day;
        }
    } 
    return time;
}
 
void display(int time) {    //显示时间 
    int a,b,c;
    a = time/hour;
    time = time % hour;
    b = time / minutes;
    time = time % minutes;
    c = time;
    printf("%02d:%02d:%02d\n",a,b,c);
}
 
int main() {
    int h1,m1,s1,h2,m2,s2;
    int t;
    scanf("%d",&t);
    while(t--) {
        int start1 = start();
        int end1 = end();
        int start2 = start();
        int end2 = end();
        int ans = 0;
        ans = (end1 - start1) + (end2 - start2);  //相加 
        display(ans/2);    //除2 
    }
    return 0;
}

【三体攻击】差分!中等难度

三体攻击 - 蓝桥云课 (lanqiao.cn)

 有难度的,暂不深入!

#include<iostream>
using namespace std;
const int N = 1000005;
int A, B, C, n, m;
int D[N];//三维差分数组 压维
int s[N];//存储舰队生命值
int x_1[N], y_1[N], z_1[N];//存储三体人的打击范围
int x_2[N], y_2[N], z_2[N];//存储三体人的打击范围
int d[N];//存储伤害
//将三维坐标转换为一维
int num(int x, int y, int z) {
    if (x > A || y > B || z > C)return 0;
    return ((x - 1) * B + (y - 1)) * C + (z - 1) + 1;
}
bool check(int x) {
    for (int i = 1;i <= n;i++)D[i] = 0;
    for (int i = 1;i <= x;i++) {
        D[num(x_1[i], y_1[i], z_1[i])]+=d[i];
        D[num(x_2[i] + 1, y_1[i], z_1[i])]-= d[i];
        D[num(x_1[i], y_2[i] + 1, z_1[i])]-= d[i];
        D[num(x_1[i], y_1[i], z_2[i] + 1)]-= d[i];
        D[num(x_2[i] + 1, y_2[i] + 1, z_1[i])]+= d[i];
        D[num(x_2[i] + 1, y_1[i], z_2[i] + 1)]+= d[i];
        D[num(x_1[i], y_2[i] + 1, z_2[i] + 1)]+= d[i];
        D[num(x_2[i] + 1, y_2[i] + 1, z_2[i] + 1)]-= d[i];
    }
    //将x,y看为定轴 对z进行累加
    for (int i = 1;i <= A;i++) {
        for (int j = 1;j <= B;j++) {
            for (int k = 1;k <= C;k++) {
                D[num(i, j, k + 1)] += D[num(i, j, k)];
            }
        }
    }
    //将x,z看为定轴 对y进行累加
    for (int k = 1;k <= C;k++) {
        for (int i = 1;i <= A;i++) {
            for (int j = 1;j <= B;j++) {
                D[num(i, j + 1, k)] += D[num(i, j, k)];
            }
        }
    }
    //将y,z看为定轴 对x进行累加
    for (int j = 1;j <= B;j++) {
        for (int k = 1;k <= C;k++) {
            for (int i = 1;i <= A;i++) {
                D[num(i + 1, j, k)] += D[num(i, j, k)];
            }
        }
    }
    for (int i = 1;i <= n;i++) {
        if (D[i] > s[i])return true;
    }
    return false;
}
int main() {
    cin >> A >> B >> C >> m;
    n = A * B * C;
    for (int i = 1;i <= n;i++) cin >> s[i];
    for (int i = 1;i <= m;i++) {
        cin >> x_1[i] >> x_2[i] >> y_1[i] >> y_2[i] >> z_1[i] >> z_2[i] >> d[i];
    }
    int L = 1;
    int R = m;
    while (L < R) {
        int mid = (L + R) >> 1;
        if (check(mid))R = mid;
        else L = mid + 1;
    }
    cout << L << endl;
    return 0;
}

【全球变暖】dfs/连通块+计数

dfs:深度优先遍历,问题1:递归深度深,栈内存不足!

bfs:宽度优先遍历,对象队列-官方

#include<bits/stdc++.h>
using namespace std;
int N;
const int SIZE = 1e4+4; 
char area[SIZE][SIZE];
bool flag;
int cnt; 
int d[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
//注意:求的是被淹没的岛屿的数量   总岛屿数量-被淹没的岛屿的数量 
int ans=0;            //没有被淹没岛屿的数量 
int res_ans=0;        //岛屿的总数量 
//用DFS判断搜到的这个岛屿会不会被淹没,仅此而已,不需要返回什么 昨判断关系
void dfs(int x,int y)
{
    //一个岛屿只要有一个点满足就不会变淹没了
    if(flag==false){  
        cnt = 0;
    for(int i=0; i<4; i++){
        int tx=d[i][0]+x;
        int ty=d[i][1]+y;
        //四面环海 
        if(area[tx][ty]!='.')
        cnt++;
    }
    
    //有一个点满足不会被淹没的条件
    if(cnt==4){
        ans++;
        flag=true;//这个岛屿不需要再遍历了
         }
    }
    area[x][y]='*';//将遍历过的点变为 *,下一次就不会遍历他了,所以不用标记数组
    //注意这里不可以是‘.’因为上面if(area[tx][ty]!='.')cnt++
    for(int i=0;i<4;i++){
         int xx = x + d[i][0];
         int yy = y + d[i][1];
         //当前岛屿连接其他岛屿 
         if(area[xx][yy]=='#'&&x<N&&x>=0&&y<N&&y>=0)
         dfs(xx,yy);
    }
}
 
int main()
{    
    cin>>N; 
    //输入海洋和陆地的情况 
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
            cin>>area[i][j];
    //遍历查找陆地的位置情况       
    for(int i=0; i<N; i++){ 
        for(int j=0; j<N; j++){
            if(area[i][j]=='#'){
                res_ans++;
                flag=false;
                //判断当前岛屿会不会淹没 
                dfs(i,j);
            }
        }
    }        
    cout<<res_ans-ans;    
    return 0;
}

【倍数问题】暴力/数论/构造

倍数问题 - 蓝桥云课 (lanqiao.cn)

蓝桥杯第 8-10 届真题解析 - 2018 年省赛真题 9 倍数问题-(思路 + C) - 蓝桥云课 (lanqiao.cn)

众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

根据规模拿分,暴力就暴力吧

 自行加强,考前再看把。。。。。。

//基础分??
#include<bits/stdc++.h>
using namespace std;
int main(){
	//n个正整数,选数要求是K的倍数 
	int n,k;
	cin>>n>>k;
	int a[n];
	for(int i=0; i<n; i++){
		cin>>a[i];
	} 
	//符合条件的三个数和sum,最大的记为max
	int sum=0; 
	int maxsum=0; 
	for(int i=0; i<n; i++){
		for(int j=i+1; j<n; j++){
			for(int z=j+1; z<n; z++){
				sum = a[i]+a[j]+a[z];
				if(sum%3==0) maxsum=max(sum,maxsum);				
			}
		}
	}
	
	cout<<maxsum<<endl;
	return 0;
} 

【付账问题】贪心

蓝桥杯第 8-10 届真题解析 - 2018 年省赛真题 10 付账问题 - 蓝桥云课 (lanqiao.cn)

 

考前复习

贪心法:

  1. 准备贪心:先将花费数组从小到大排序
  2. 贪心策略:
    1. 从数组最小的元素开始,每次做判断
    2. 若当前元素小于剩余花费平均值,则取该元素不改变值,将平均成本转嫁到后续元素上
    3. 若当前元素大于等于剩余花费平均值,则后续元素也大于该平均值,能够承接前较小元素的成 本,将当前元素之后的所有元素取剩余花费平均值
  3. 结束贪心,解出标准差

精确度:

本题对于精确度要求较高,总结如下提升准确度的方法

  1. long long提升整数的准确度
  2. double可以承接18位左右有效数字
  3. 尽量减少除法,转换成乘法
  4. 尽量减少会导致误差的计算的次数
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;

int main(){
  ll N;
  double S, avg = 0;
  cin >> N >> S;
  int A[500005];
  
  for(int i = 0; i < N; i++)
    cin >> A[i];
  avg = S*1.0/N;
  sort(A, A+N);

  double ans = 0;
  for(int i = 0 ;  i < N; i++){
    if(A[i]*(N-i) < S){
        ans += (avg - A[i]) * (avg - A[i]);
        S -= A[i];
    }
    else{
      double cur = S*1.0/(N-i);
      ans += (cur-avg)*(cur-avg)*(N-i);
      break;
    }
  }

  printf("%.4lf", sqrt(ans/N));
  return 0;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2018第九届C/C++ A蓝桥杯省赛真题主要包含编程题和选择题两部分。编程题考察了学生对C/C++语言的掌握以及解决实际问题的能力,选择题则涵盖了计算机科学与技术的基础知识。 编程题中有一道较难的题目是“最短路径问题”。该题给出了一个有向图,要求求解出从起点到终点的最短路径。这道题需要学生运用图论中的最短路径算法,比如迪杰斯特拉算法或贝尔曼-福特算法来解决,需要高度的编程能力和算法思维能力。 除了编程题外,选择题考察了计算机科学与技术的基础知识,包括数据结构、算法、操作系统、计算机网络等方面。例如,有一道关于排序算法的选择题,要求学生判断给定的排序算法是否满足时间复杂度为O(nlogn)的条件,需要对常见的排序算法,如快速排序、归并排序等进行了解和分析。 蓝桥杯是一个针对大学生的计算机比赛,旨在提高学生的编程能力和解决实际问题的能力。每都会有数以万计的大学生参加,竞争十分激烈。参加蓝桥杯不仅可以提升自己的编程技术水平,还有机会获得奖金和荣誉,对以后的学习和就业都有很大的帮助。 总之,2018第九届C/C++ A蓝桥杯省赛真题涵盖了C/C++语言的应用和计算机科学与技术的基础知识。通过参加这样的比赛,可以提高自己的编程能力,同时也为今后的学习和发展打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MengYa_DreamZ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值