2018 蓝桥杯第五次模拟赛题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lujie_1996/article/details/79696417

昨天下午,我简单地看了下蓝桥杯省赛模拟赛的题。硬生生地应付完了,结果拿了 34/1000+ 名,不知道是惊喜还是惊吓?

题目来源:https://www.jisuanke.com/contest/1215

A. 结果填空:矩阵求和

给你一个从n*n的矩阵,里面填充1到n*n。例如当n等于3的时候,填充的矩阵如下。

 1 2 3
 4 5 6
 7 8 9

现在我们把矩阵中的每条边的中点连起来,这样形成了一个新的矩形,请你计算一下这个新的矩形的覆盖的数字的和。比如,n=3的时候矩形覆盖的数字如下。

   2
 4 5 6
   8

那么当n等于101的时候,矩阵和是多少?

分析

把题目读错了,以为是求中点连成的十字架数字之和,其实非也,是类似菱形覆盖的数字之和。以矩形的中心((N-1)/2, (N-1)/2)为原点,菱形中数字的横纵坐标之和到原点的距离小于或等于矩形半径。

代码

#include <stdio.h>
#include <stdlib.h>
#define N 101
int main(void)
{
	int index = 0;

	long long int sum = 0L;
	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N;j++)
		{
			++index;
			if(abs((i-(N-1)/2))+abs((j-(N-1)/2)) <= (N-1)/2)
			{
				sum += index;
				//printf("%d\n", index);
			}
		}
	}	
	printf("%lld\n", sum);
	
	return 0;
}

答案:26020201

B. 结果填空:素数个数

用0,1,2,3…7这8个数字组成的所有整数中,质数有多少个(每个数字必须用到且只能用一次)。

提示:以0开始的数字是非法数字。


分析

暴力枚举所有数字,并判断

代码

#include <stdio.h>
#include <math.h>
int main(void)
{
	int cnt = 0;
	for(int a = 1;a < 8;a++)
		for(int b = 0;b < 8;b++)
			for(int c = 0;c < 8;c++)
				for(int d = 0;d < 8;d++)
					for(int e = 0;e < 8;e++)
						for(int f = 0;f < 8;f++)
							for(int g = 0;g < 8;g++)
								for(int h = 0;h < 8;h++)
								{
									if(a!=b && a!=c && a!=d && a!=e && a!=f && a!=g && a!=h
											&& b!=c && b!=d && b!=e && b!=f && b!=g && b!=h
													&& c!=d && c!=e && c!=f && c!=g && c!=h
															&& d!=e && d!=f && d!=g && d!=h
																	&& e!=f && e!=g && e!=h
																		 	&& f!=g && f!=h
																			 		&& g!=h)
									{
										int i = a*10000000+b*1000000+c*100000+d*10000+e*1000+f*100+g*10+h;
										bool flag = true;
										for(int k = 2;k <= sqrt(i)+0.5;k++)
										{
											if(i%k == 0)
											{
												flag = false;
												break;
											}
										}
										if(flag)
										{	
											cnt++;
										}
									}
								}
	printf("%d\n",cnt);
	
	return 0;
}


答案:2668

C.  结果填空:连连看

1

4

2

5

2

1

2

1

3

1

3

2

2

5

3

4

我们可以把任意两个在图的边界上相同的方格一起消掉,每次消掉两个方格的时候,都会获得一个分数,第i次消的分数为i*方格的值。

请你帮忙最优操作情况下,获得的分数最多为多少。

分析

DFS搜索

答案:89

D.  代码填空:快速幂

一个数的整数次幂,是我们在计算中经常用到的,但是怎么可以在O(log(n))的时间内算出结果呢?

代码框中的代码是一种实现,请分析并填写缺失的代码,求xymod p 的结果。

#include <iostream>
using namespace std;

int pw(int x, int y, int p) {
    if (!y) {
        return 1;
    }
    int res = /*在这里填写必要的代码*/;
    if (y & 1) {
        res = res * x % p;
    }
    return res;
}

int main() {
    int x, y, p;
    cin >> x >> y >> p;
    cout << pw(x, y, p) << endl;
    return 0;
}

答案:pw(x,y>>1,p)*pw(x,y>>1,p)%p(或者pw(x,y/2,p)*pw(x,y/2,p)%p)

E. 代码填空:末尾零的个数

N!末尾有多少个0呢?

N! = 1*2*…*N。

代码框中的代码是一种实现,请分析并填写缺失的代码。

#include <iostream>
using namespace std;
int main() {
    int n, ans = 0;
    cin >> n;
    while (n) {
        ans += /*在这里填写必要的代码*/;
    }
    cout << ans << endl;
    return 0;
}

答案:(n/=5)

F. 结果填空:藏宝图

蒜头君得到一张藏宝图。藏宝图是一个10*10 的方格地图,图上一共有10 个宝藏。有些方格地形太凶险,不能进入。

整个图只有一个地方可以出入,即是入口也是出口。蒜头君是一个贪心的人,他规划要获得所有宝藏以后才从出口离开。

藏宝图上从一个方格到相邻的上下左右的方格需要1 天的时间,蒜头君从入口出发,找到所有宝藏以后,回到出口,最少需要多少天。

分析

自己手算的,注意最后要回到出入点

答案:48

G. 程序设计:合并数字

蒜头君得到了 n 个数,他想对这些数进行下面这样的操作,选出最左边的相邻的差的绝对值为 1 的两个数,只保留较小的数,删去较大的数,直到没有两个相邻的差的绝对值为 1 的数,问最多可以进行多少次这样的操作?

输入格式

输入第一行为一个整数 n(1≤n ≤ 105),表示数字的总数

第二行为 n 个整数 x1,x2,...,xn (0≤xi≤10),表示这些数。

输出格式

输出一行,为一个整数,表示蒜头君最多可以进行多少次这样的操作。

样例输入

4

1 2 0 1

样例输出

3

分析

第一次使用的是暴力法,一直反复检测到所有数据全部一致就OK,但是只能通过一组数据,其余九组全部超时。于是改用栈来维护合并的数。

代码

#include <stdio.h>
#include <stack>
using namespace std;
int main(void)
{
	int n;
	scanf("%d", &n);
	stack<int> s;
	int cnt = 0;
	for(int i = 0;i < n;i++)
	{
		int a;
		scanf("%d", &a);
		while(!s.empty() && s.top() - a == 1)
		{
			s.pop();
			cnt ++;
		}
		if(!s.empty() && a - s.top() == 1)
		{
			cnt ++;
		}
		else
		{
			s.push(a);
		}
	}
	printf("%d\n", cnt);
	
	return 0;
}


注意:while(!s.empty() && s.top() - a == 1)使用的是while,一直以为if也可以,但是过不了数据3 3 3 3 2。

H. 程序设计:蒜头君下棋

蒜头君喜欢下棋。最近它迷上了国际象棋。国际象棋的棋盘可以被当做一个 8*8 的矩阵,棋子被放在格子里面(不是和中国象棋一样放在线上)。

蒜头君特别喜欢国际象棋里面的马,马的移动规则是这样的:横着走两步之后竖着走一步,或者横着走一步之后竖着走两步。例如,一匹马在 (3,3) 的位置,则它可以到达的地方有 (1,2), (2,1), (1,4),(4,1), (5,2), (2,5), (5,4), (4,5) 八个地方。蒜头君想要把整个棋盘都放上马,并且让这些马不能相互攻击(即任何一匹马不能走一步之后就到达另一匹马的位置)。蒜头君当然知道在 8 *8 的棋盘上怎么放马,但如果棋盘变为 n*m 的,蒜头君就不懂了。他希望你来帮忙他计算一下究竟能放多少匹马。

输入格式

共一行,两个整数n和m( 1≤n , m≤1000),代表棋盘一共有 n 行 m 列。

输出格式

输出一个整数,代表棋盘上最多能放的马的数量。

样例输入1

2 4

样例输出1

4

样例输入2

3 4

样例输出2

6

分析

假设行数n <= 列数m,

当行数n=1时,最大放马数为列数m;

当行数n=2时,最大放马数为放两列空两列(注意如何计算);

当行数n>2时,最大方马数为国际棋盘样式(注意要m*n+1);

代码

#include <stdio.h>
#include <iostream>
using namespace std;
int main(void)
{
	int n, m;
	scanf("%d%d", &n,&m);
	if(n > m)
	{
		int t = n;
		n = m;
		m = t;
	}
	if(n == 1)
	{
		printf("%d\n", m);
	}
	else if(n == 2)
	{
		printf("%d\n", m/4*4+min(m%4,2)*2);
	}
	else
	{
		printf("%d\n", (n*m+1)/2);
	}
	
	return 0;
}

I. 程序设计:蒜头君的数轴

今天蒜头君拿到了一个数轴,上边有 n 个点,但是蒜头君嫌这根数轴不够优美,想要通过加一些点让它变优美,所谓优美是指考虑相邻两个点的距离,最多只有一对点的距离与其它的不同。

蒜头君想知道,他最少需要加多少个点使这个数轴变优美。

输入格式

输入第一行为一个整数 n(1≤n≤105),表示数轴上的点数。

第二行为 nn 个不重复的整数 x1,x2,...,xn(−109≤xi≤109),表示这些点的坐标,点坐标乱序排列。

输出格式

输出一行,为一个整数,表示蒜头君最少需要加多少个点使这个数轴变优美。

样例输入

4

1 3 7 15

样例输出

1

分析

不会

J. 程序设计:划分整数

蒜头君特别喜欢数学。今天,蒜头君突发奇想:如果想要把一个正整数 n 分解成不多于 k 个正整数相加的形式,那么一共有多少种分解的方式呢?

蒜头君觉得这个问题实在是太难了,于是他想让你帮帮忙。

输入格式

共一行,包含两个整数 n (1≤n≤300) 和 k (1≤k≤300),含义如题意所示。

输出格式

一个数字,代表所求的方案数。

样例输入

5 3

样例输出

5

分析

之前采用的循环+递归,过了大半样例,其余超时,后改用纯递归,超时更严重了……就用循环吧!注意结果使用longlong int来保存,不然会爆!

当n=1 || k=1时,f(n, k) = 1;

当n < k 时,f(n, k) = f(n, n);

当n = k 时,f(n, k) = f(n, k-1) + 1;

当n > k 时,f(n ,k) = f(n, k-1) + f(n-k, k);

循环+递归代码(超时)

#include <stdio.h>
int f(int n,int k)
{
	if(n == k)	return 1;
	if(n < k)	return 0;
	if(n == 1 || k == 1)	return 1;
	return f(n-1,k-1)+f(n-k,k);
}
int main(void)
{
	int n,k;
	scanf("%d%d", &n,&k);
	int res = 0;
	for(int i = 1;i <= k;i++)
	{
		res += f(n,i);
	}
	printf("%d\n", res);
	
	return 0;
}

纯循环

#include <stdio.h>
int main(void)
{
	int n,k;
	long long int a[320][320];
	scanf("%d%d", &n, &k);
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= k;j++)
		{
			if(i == 1 || j == 1)
				a[i][j] = 1;
			if(i < j)
				a[i][j] = a[i][i];
			if(i == j)
				a[i][j] = a[i][j-1] + 1;
			if(i > j)
				a[i][j] = a[i][j-1] + a[i-j][j];
		}
	}
	printf("%lld\n", a[n][k]);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lujie_1996/article/details/79696417
今日推荐