C/C++ 第七届蓝桥杯大赛个人赛省赛(大学A组) 题解

题目类型
网友年龄结果填空
生日蜡烛结果填空
方格填数结果填空
快速排序代码填空
消除尾一代码填空
寒假作业结果填空
剪邮票结果填空
四平方和程序设计
密码脱落程序设计
最大比例程序设计

1. 网友年龄

  • 本题总分:3分

  • 问题描述

    某君新认识一网友。
    当问及年龄时,他的网友说:
    “我的年龄是个2位数,我比儿子大27岁,
    如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”

    请你计算:网友的年龄一共有多少种可能情况?

    提示:30岁就是其中一种可能哦.

    请填写表示可能情况的种数。

  • 注意

    你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


  • 解析

    #include<iostream>
    using namespace std;
    int main()
    {
    	int ans = 0;
    	for (int dad = 27; dad <= 99; dad++)
    	{
    		int son = dad % 10 * 10 + dad / 10;
    		if (dad - son == 27) ans++;
    	}
    	cout << ans;
    	return 0;
    }
    
  • 答案

    7


2. 生日蜡烛

  • 本题总分:5分

  • 问题描述

    某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

    现在算起来,他一共吹熄了236根蜡烛。

    请问,他从多少岁开始过生日party的?

    请填写他开始过生日party的年龄数。

  • 注意

    你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


  • 解析

    #include<iostream>
    using namespace std;
    int main()
    {
    	bool find = false;
    	for (int i = 1; i <= 100; i++)
    	{
    		int sum = 0;
    		for (int j = i; j <= 100; j++)
    		{
    			sum += j;
    			if (sum == 236)
    			{
    				cout << i;
    				find = true;
    				break;
    			}
    		}
    		if (find) break;
    	}
    	return 0;
    }
    
  • 答案

    26


3. 方格填数

  • 本题总分:11分

  • 问题描述

    如下的10个格子

    在这里插入图片描述

    填入0~9的数字。要求:连续的两个数字不能相邻。
    (左右、上下、对角都算相邻)

    一共有多少种可能的填数方案?

    请填写表示方案数目的整数。

  • 注意

    你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


  • 解析

    #include<iostream>
    using namespace std;
    int map[6][6];
    int ans;
    bool vis[10];
    
    bool check(int x, int y, int n)
    {
    	if (vis[n]) return false;
    	if (x < 1 || x > 3) return false;
    	if (y < 1 || y > 4) return false;
    	if (map[x][y] != 0) return false;
    	if (abs(map[x][y - 1] - n) <= 1) return false;
    	if (abs(map[x - 1][y] - n) <= 1) return false;
    	if (abs(map[x - 1][y - 1] - n) <= 1) return false;
    	if (abs(map[x - 1][y + 1] - n) <= 1) return false;
    	return true;
    }
    
    void dfs(int x, int y)
    {
    	//遍历数字
    	for (int i = 0; i <= 9; i++)
    	{
    		
    		int x0, y0;
    		//如果到了最后一列
    		if (y == 4)
    		{
    			x0 = x + 1;
    			y0 = 1;
    		}
    		//一般情况
    		else
    		{
    			x0 = x;
    			y0 = y + 1;
    		}
    		//到达最后一个格
    		if (x0 == 3 && y0 == 4)
    		{
    			ans++;
    			return;
    		}
    		//满足条件,进行深搜
    		if (check(x0, y0, i))
    		{
    			map[x0][y0] = i;
    			vis[i] = true;
    
    			dfs(x0, y0);
    
    			map[x0][y0] = 0;
    			vis[i] = false;
    		}
    	}
    }
    
    int main()
    {
    	//初始化地图
    	memset(map, 10, sizeof(map));
    	//3*4的地图
    	for (int i = 1; i <= 3; i++)
    	{
    		for (int j = 1; j <= 4; j++)
    		{
    			map[i][j] = 0;
    		}
    	}
    	//左上角和右下角的方格
    	map[1][1] = -2;
    	map[3][4] = -2;
    
    	dfs(1, 1);
    	cout << ans;
    	return 0;
    }
    
  • 答案

    1580


4. 快速排序

  • 本题总分:9分

  • 问题描述

    排序在各种场合经常被用到。
    快速排序是十分常用的高效率的算法。

    其思想是:先选一个“标尺”,
    用它把整个队列过一遍筛子,
    以保证:其左边的元素都不大于它,其右边的元素都不小于它。

    这样,排序问题就被分割为两个子区间。
    再分别对子区间排序就可以了。

    下面的代码是一种实现,请分析并填写划线部分缺少的代码。

    #include <stdio.h>
    
    void swap(int a[], int i, int j)
    {
    	int t = a[i];
    	a[i] = a[j];
    	a[j] = t;
    }
    
    int partition(int a[], int p, int r)
    {
        int i = p;
        int j = r + 1;
        int x = a[p];
        while(1){
            while(i<r && a[++i]<x);
            while(a[--j]>x);
            if(i>=j) break;
            swap(a,i,j);
        }
    	______________________;
        return j;
    }
    
    void quicksort(int a[], int p, int r)
    {
        if(p<r){
            int q = partition(a,p,r);
            quicksort(a,p,q-1);
            quicksort(a,q+1,r);
        }
    }
        
    int main()
    {
    	int i;
    	int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
    	int N = 12;
    	
    	quicksort(a, 0, N-1);
    	
    	for(i=0; i<N; i++) printf("%d ", a[i]);
    	printf("\n");
    	
    	return 0;
    }
    
  • 注意

    只填写缺少的内容,不要书写任何题面已有代码或说明性文字。

  • 答案

    swap(a, p, j);  //将最初的基准值与之后返回的下标对应的数据进行交换
    

5. 消除尾一

  • 本题总分:13分

  • 问题描述

    下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
    如果最后一位是0,则原数字保持不变。

    如果采用代码中的测试数据,应该输出:
    00000000000000000000000001100111 00000000000000000000000001100000
    00000000000000000000000000001100 00000000000000000000000000001100

    请仔细阅读程序,填写划线部分缺少的代码。

    #include <stdio.h>
    
    void f(int x)
    {
    	int i;
    	for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
    	printf("   ");
    	
    	x = _______________________;
    	
    	for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
    	printf("\n");	
    }
    
    int main()
    {
    	f(103);
    	f(12);
    	return 0;
    }
    
  • 注意

    只填写缺少的内容,不要书写任何题面已有代码或说明性文字。

  • 答案

    x & (x + 1)
    

6. 寒假作业

  • 本题总分:15分

  • 问题描述

    现在小学的数学题目也不是那么好玩的。
    看看这个寒假作业:

    在这里插入图片描述

    每个方块代表1~13中的某一个数字,但不能重复。
    比如:
    6 + 7 = 13
    9 - 8 = 1
    3 * 4 = 12
    10 / 2 = 5

    以及:
    7 + 6 = 13
    9 - 8 = 1
    3 * 4 = 12
    10 / 2 = 5

    就算两种解法。(加法,乘法交换律后算不同的方案)

    你一共找到了多少种方案?

    请填写表示方案数目的整数。

  • 注意

    你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


  • 解析

    #include<iostream>
    using namespace std;
    int a[5][3];
    bool vis[14];
    int ans;
    
    bool check(int x, int y, int n)
    {
    	if (a[x][y] != 0) return false;//该点已遍历过
    	if (vis[n]) return false;//该数字已使用过
    	if (x < 1 || x > 4) return false;//越界
    	if (y < 1 || y > 2) return false;//越界
    	if (x == 1 && y == 2)
    	{
    		if ((a[x][1] + n) < 1 || (a[x][1] + n) > 13) return false;//结果越界
    		if (a[x][1] + n == a[x][1] || a[x][1] + n == n) return false;//结果与前2个数之一相等
    		if (vis[a[x][1] + n]) return false;//结果的数字已使用过
    	}
    	if (x == 2 && y == 2)
    	{
    		if ((a[x][1] - n) < 1 || (a[x][1] - n) > 13) return false;//结果越界
    		if (a[x][1] - n == a[x][1] || a[x][1] - n == n) return false;//结果与前2个数之一相等
    		if (vis[a[x][1] - n]) return false;//结果的数字已使用过
    	}
    	if (x == 3 && y == 2)
    	{
    		if ((a[x][1] * n) < 1 || (a[x][1] * n) > 13) return false;//结果越界
    		if (a[x][1] * n == a[x][1] || a[x][1] * n == n) return false;//结果与前2个数之一相等
    		if (vis[a[x][1] * n]) return false;//结果的数字已使用过
    	}
    	if (x == 4 && y == 2)
    	{
    		if (a[x][1] % n != 0) return false;//不能被整除
    		if ((a[x][1] / n) < 1 || (a[x][1] / n) > 13) return false;//结果越界
    		if (a[x][1] / n == a[x][1] || a[x][1] / n == n) return false;//结果与前2个数之一相等
    		if (vis[a[x][1] / n]) return false;//结果的数字已使用过
    	}
    	return true;
    }
    
    void sign(int x, int y, bool sign)
    {
    	//标记结果的数字
    	if (x == 1 && y == 2) vis[a[x][1] + a[x][2]] = sign;
    	else if (x == 2 && y == 2) vis[a[x][1] - a[x][2]] = sign;
    	else if (x == 3 && y == 2) vis[a[x][1] * a[x][2]] = sign;
    	else if (x == 4 && y == 2) vis[a[x][1] / a[x][2]] = sign;
    }
    
    void dfs(int x, int y)
    {
    	//如果已使用了12个数字,说明已完成一次遍历。ans++
    	int sum = 0;
    	for (int i = 1; i <= 13; i++)
    	{
    		if (vis[i]) sum++;
    	}
    	if (sum == 12)
    	{
    		ans++;
    		return;
    	}
    
    	for (int i = 1; i <= 13; i++)
    	{
    		int x0, y0;
    		if (y == 2)
    		{
    			x0 = x + 1;
    			y0 = 1;
    		}
    		else
    		{
    			x0 = x;
    			y0 = y + 1;
    		}
    		if (check(x0, y0, i))
    		{
    			a[x0][y0] = i;
    			vis[i] = true;
    			sign(x0, y0, true);
    
    			dfs(x0, y0);
    
    			vis[i] = false;
    			sign(x0, y0, false);
    			a[x0][y0] = 0;
    		}
    	}
    }
    
    int main()
    {
    	dfs(1, 0);
    	cout << ans;
    	return 0;
    }
    
  • 答案

    64


7. 剪邮票

  • 本题总分:19分

  • 问题描述

    如图,有12张连在一起的12生肖的邮票。

    在这里插入图片描述

    现在你要从中剪下5张来,要求必须是连着的。
    (仅仅连接一个角不算相连)

    比如,下两图中,粉红色所示部分就是合格的剪取。

    在这里插入图片描述

    在这里插入图片描述

    请你计算,一共有多少种不同的剪取方法。

    请填写表示方案数目的整数。

  • 注意

    你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


  • 解析

    #include<iostream>
    #include<algorithm>
    using namespace std;
    char a[4][5];		//用于存放1-12
    bool vis[4][5];
    string Sfind[1005];	//用于存放已找到的裁剪方式
    string s_black;		//空字符串
    int ans;			//答案
    int cnt;			//Sfind数组计数
    int dx[4] = { 0, 0, 1, -1 };
    int dy[4] = { 1, -1, 0, 0 };
    
    //检查下一步的正确性
    bool check(int x, int y)
    {
    	if (vis[x][y]) return false;
    	if (x < 1 || x > 3) return false;
    	if (y < 1 || y > 4) return false;
    	return true;
    }
    
    //检查记录的s是否已到达5个,并且和之前的没有重复
    bool check_s(string s)
    {
    	sort(s.begin(), s.end());//排序s,便于对比
    	if (s.length() != 5) return false;
    	if (s.length() == 5)
    	{
    		for (int i = 0; i < 1005; i++)
    		{
    			if (Sfind[i] == s) return false;
    		}
    	}
    	Sfind[cnt++] = s;
    	return true;
    }
    
    void dfs(int x, int y, string s)
    {
    	if (check_s(s))
    	{
    		ans++;
    		return;
    	}
    
    	for (int i = 0; i < 4; i++)
    	{
    		int x0 = x + dx[i];
    		int y0 = y + dy[i];
    
    		if (check(x0, y0))
    		{
    			vis[x0][y0] = 1;
    			dfs(x0, y0, s + a[x0][y0]);
    			vis[x0][y0] = 0;
    		}
    	}
    }
    
    int main()
    {
    	//初始化1-12,而使用str记录,因此用char初始化
    	char c = 'a';
    	for (int i = 1; i <= 3; i++)
    	{
    		for (int j = 1; j <= 4; j++)
    		{
    			a[i][j] = c++;
    		}
    	}
    
    	//每个点都作为开头进行遍历
    	for (int i = 1; i <= 3; i++)
    	{
    		for (int j = 1; j <= 4; j++)
    		{
    			memset(vis, 0, sizeof(vis));
    			vis[i][j] = 1;
    			dfs(i, j, s_black + a[i][j]);
    		}
    	}
    
    	cout << ans;
    	return 0;
    }
    
  • 答案

    82


8. 四平方和

  • 本题总分:21分

  • 问题描述

    四平方和定理,又称为拉格朗日定理:
    每个正整数都可以表示为至多4个正整数的平方和。
    如果把0包括进去,就正好可以表示为4个数的平方和。

    比如:
    5 = 02 + 02 + 12 + 22
    7 = 12 + 12 + 12 + 22

    对于一个给定的正整数,可能存在多种平方和的表示法。
    要求你对4个数排序:
    0 <= a <= b <= c <= d
    并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

  • 输入格式

    程序输入为一个正整数N (N<5000000)

  • 输出格式

    要求输出4个非负整数,按从小到大排序,中间用空格分开

  • 样例输入

    5

  • 样例输出

    0 0 1 2

  • 样例输入

    12

  • 样例输出

    0 2 2 2

  • 样例输入

    773535

  • 样例输出

    1 1 267 838

  • 资源约定

    峰值内存消耗 < 256M
    CPU消耗 < 3000ms

  • 注意

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    main函数需要返回0
    只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。


  • 答案

    #include<iostream>
    using namespace std;
    int main()
    {
    	int n;
    	cin >> n;
    	bool flag = false;
    	for (int i = 0; i < 2306; i++)
    	{
    		if (flag) break;
    		for (int j = i; j < 2306; j++)
    		{
    			if (flag) break;
    			for (int k = j; k < 2306; k++)
    			{
    				if (flag) break;
    				for (int l = k; l < 2306; l++)
    				{
    					int t = i * i + j * j + k * k + l * l;
    					if (t == n)
    					{
    						cout << i << " " << j << " " << k << " " << l << endl;
    						flag = true;
    						break;
    					}
    				}
    			}
    		}
    	}
    	return 0;
    }
    

9. 密码脱落

  • 本题总分:25分

  • 问题描述

    X星球的考古学家发现了一批古代留下来的密码。
    这些密码是由A、B、C、D 四种植物的种子串成的序列。
    仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
    由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。

    你的任务是:
    给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。

  • 输入格式

    输入一行,表示现在看到的密码串(长度不大于1000)

  • 输出格式

    要求输出一个正整数,表示至少脱落了多少个种子。

  • 样例输入

    ABCBA

  • 样例输出

    0

  • 样例输入

    ABDCDCBABC

  • 样例输出

    3

  • 资源约定

    峰值内存消耗 < 256M
    CPU消耗 < 1000ms

  • 注意

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    main函数需要返回0
    只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。


  • 答案

    #include<iostream>
    using namespace std;
    string s;
    int ans = 0x3f3f3f;
    
    void dfs(int l, int r, int len)
    {
    	if (l >= r)
    	{
    		if (ans > len) ans = len;
    		return;
    	}
    	//相等
    	if (s[l] == s[r]) dfs(l + 1, r - 1, len);
    	//不相等
    	else
    	{
    		dfs(l + 1, r, len + 1);
    		dfs(l, r - 1, len + 1);
    	}
    }
    
    int main()
    {
    	cin >> s;
    	dfs(0, s.length() - 1, 0);
    	cout << ans;
    	return 0;
    }
    

10. 最大比例

  • 本题总分:29分

  • 问题描述

    X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
    并且,相邻的两个级别间的比例是个固定值。
    也就是说:所有级别的奖金数构成了一个等比数列。比如:
    16,24,36,54
    其等比值为:3/2

    现在,我们随机调查了一些获奖者的奖金数。
    请你据此推算可能的最大的等比值。

  • 输入格式

    第一行为数字 N (0<N<100),表示接下的一行包含N个正整数
    第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额

  • 输出格式

    一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数

    测试数据保证了输入格式正确,并且最大比例是存在的。

  • 样例输入

    3
    1250 200 32

  • 样例输出

    25/4

  • 样例输入

    4
    3125 32 32 200

  • 样例输出

    5/2

  • 样例输入

    3
    549755813888 524288 2

  • 样例输出

    4/1

  • 资源约定

    峰值内存消耗 < 256M
    CPU消耗 < 3000ms

  • 注意

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    main函数需要返回0
    只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。


  • 答案

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <string.h>
    
    int N;
    long long bonus[100];
    long long res[100], p1[100], p2[100];
    long long num1, num2;
    
    void sort()
    {
        long long tmp;
        for(int i=0;i<N;i++)
        {
            for(int j=i+1;j<N;j++)
            {
                if( bonus[j] < bonus[i] )
                {
                    tmp = bonus[j];
                    bonus[j] = bonus[i];
                    bonus[i] = tmp;
                }
            }
        }
    }
    
    void removeSame()
    {
        int k = 1;
        res[0] = bonus[0];
        for(int i=1;i<N;i++)
        {
            if( bonus[i] == bonus[i-1] )
                continue;
            res[k++] = bonus[i];
        }
        N = k;
    
    }
    
    long long gcd(long long a, long long b)
    {
        long long t;
        if( b == 0 )
            return a;
        else
            return gcd( b, a%b );
    }
    
    long long max(long long a, long long b)
    {
        return a >= b ? a : b;
    }
    
    long long min(long long a, long long b)
    {
        return a <= b ? a : b;
    }
    
    void solve()
    {
        int tmp;
        int k;
        if( N == 1 )
        {
            num1 = 1;
            num2 = 1;
            return;
        }
        else if( N == 2 )
        {
            tmp = gcd( res[1], res[0] );
            num1 = res[1] / tmp;
            num2 = res[0] / tmp;
            return;
        }
        else
        {
            k = 0;
            long long g,g1,g2;
            for(int i=1;i<N;i++)
            {
                tmp = gcd( res[i], res[i-1] );
                p1[k] = res[i] / tmp;
                p2[k] = res[i-1] / tmp;
                k++;
            }
        }
        double t = 999999; // 存储最小的公约数 
        long long  t1, t2, tt1, tt2, max_tmp, min_tmp;
        long long max_p1, max_p2, min_p1, min_p2;
        for(int i=0;i<N-1;i++)
        {
            for(int j=i+1;j<N-1;j++)
            {
                if( p1[i]*p2[j] == p1[j]*p2[i] )
                {
                    t1 = p1[i];
                    t2 = p2[i];
                }
                else
                {
                    max_p1 = max( p1[i], p1[j] );
                    max_p2 = max( p2[i], p2[j] );
    
                    min_p1 = min( p1[i], p1[j] );
                    min_p2 = min( p2[i], p2[j] );
    
                    max_tmp = max_p1;
                    min_tmp = min_p1;
                    max_p1 = max( min_tmp, max_tmp/min_tmp );
                    min_p1 = min( min_tmp, max_tmp/min_tmp );
    
                    max_tmp = max_p2;
                    min_tmp = min_p2;
                    max_p2 = max( min_tmp, max_tmp/min_tmp );
                    min_p2 = min( min_tmp, max_tmp/min_tmp );
    
                    t1 = gcd( max_p1, min_p1 );
                    t2 = gcd( max_p2, min_p2 );
    
                }
    
                // 在之前的程序中可知p1>p2 
                if( 1.0*t1/t2 < t )
                {
                    t = 1.0*t1/t2;
                    tt1 = t1;
                    tt2 = t2;
                }
            }
        }
        tmp = gcd(tt1, tt2);
        num1 = tt1 / tmp;
        num2 = tt2 / tmp;
    }
    
    
    int main()
    {
        scanf("%d", &N);
        for(int i=0;i<N;i++)
            scanf("%lld", &bonus[i]);
        sort();
        removeSame();
    
        solve();
    
        printf("%lld/%lld\n", num1, num2);
        return 0;
    }
    

    引用:https://blog.csdn.net/u012526003/article/details/79460697

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值