15届蓝桥杯C++ B组第二场

第十五届蓝桥杯大赛软件赛省赛第二场

C/C++ 大学 B 组

【考生须知】

考试开始后,选手首先下载题目,并使用考场现场公布的解压密码解压试 题。

考试时间为 4 小时。考试期间选手可浏览自己已经提交的答案,被浏览的答案允许拷贝。时间截止后,将无法继续提交或浏览答案。

对同一题目,选手可多次提交答案,以最后一次提交的答案为准。

选手必须通过浏览器方式提交自己的答案。选手在其它位置的作答或其它 方式提交的答案无效。

试题包含“结果填空”和“程序设计”两种题型。

结果填空题:要求选手根据题目描述直接填写结果。求解方式不限。不要 求源代码。把结果填空的答案直接通过网页提交即可,不要书写多余的内容。

程序设计题:要求选手设计的程序对于给定的输入能给出正确的输出结果。 考生的程序只有能运行出正确结果才有机会得分。

注意:在评卷时使用的输入数据与试卷中给出的示例数据可能是不同的。 选手的程序必须是通用的,不能只对试卷中给定的数据有效。

对于编程题目,要求选手给出的解答完全符合 GNU C/C++ 标准,不能使用诸如绘图、Win32API、中断调用、硬件操作或与操作系统相关的 API。

代码中允许使用 STL 类库。

注意: main 函数结束必须返回 0。

注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>,不能通过工程设置而省略常用头文件。

所有源码必须在同一文件中。调试通过后,拷贝提交。 提交时,注意选择所期望的编译器类型。

 

试题 A: 进制

本题总分:5 分

【问题描述】

8100178706957568 这个数在用 x 进制表示时 (x ∈ [11, 36]),仅包含数字而不包含字母,请问 x 是多少。比如 2588 用 16 进制表示为 a1c,包含字母 a c

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

int f[1000];

int x = 32;

int y = 0;

int main(){
	long long num = 8100178706957568;//2588
	long long test = 8100178706957568;
	long long temp = 0;
	int i = 1;
	
	while(temp < test){
		temp += pow(x,i);
		i++;
	}
	temp = test;
	int bit = i - 1;//这个是这个数一共有多少位用来表示
	int cnt = i - 1;//这个是用来计数f[]的 
	for(int j = bit - 1; j >= 0; j--){
		f[cnt] = test / pow(x,j);
		test = test - f[cnt] * pow(x,j);
		cout << f[cnt] << endl;
		if(f[cnt] > 9){
			cout << " "<< "失败" << endl;
			return false;
		}
	}
	cout << "完成" << endl;
}
 

试题 B: 逆序对期望

本题总分:5 分

【问题描述】

有一个数组,包含 1 到 n n 个整数,初始为一个从小到大的有序排列:

{1, 2, 3, 4, · · · , n} 。一次随机交换操作指:均匀随机选取两个位置 i, j ∈ [1, n] 且 i j ,然后交换数组中这两个位置上的数。那么对于 n = 51 ,对初始数组进行两次随机交换操作之后,数组中的逆序对的数量的期望是多少个。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个实数,在提交答案时只填写这个实数,四舍五入保留两位小数,填写多余的 内容将无法得分。

 
不会,写的是错的
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

int f[100];

int bak[100];

int flag[100];

int cnt = 2;

int res = 0;
//194//88
void dfs(int cnt){
	if(cnt > 2){
		int time = 0;
		//计算逆序对数量
		for(int i = 1; i <= 51; i++){
			if(flag[i] == 1){
				for(int j = i; j <= 51; j++){
					if(f[i] > f[j]) time++;
				}
			}
		}
		res = max(res,time);
	}
	for(int i = 1; i<= 51; i++){
		if(flag[i] == 1) continue;
		flag[i] = 1;
		//假设第一个数从位置1开始交换
		for(int j = 1; j <= 51; j++){
			if(i == j || flag[j] == 1) continue;
			int temp = f[i];
			f[i] = f[j];
			f[j] = temp;
			flag[j] = 1;
			dfs(cnt + 1);
			//还原 
			flag[j] = 0;
			f[j] = f[i];
			f[i] = temp;
		} 
		flag[i] = 0;
	}
}

int main(){
	for(int i = 1; i <= 51; i++){
		f[i] = i;
		bak[i] = i;
	}//51个数 
	int max = 0;
	
	dfs(1);

	cout << res << endl;
}

试题 C: 传送阵

时间限制: 1.0s     内存限制: 256.0MB     本题总分:10 分

【问题描述】

小蓝在环球旅行时来到了一座古代遗迹,里面并排放置了 n 个传送阵,进入第 i 个传送阵会被传送到第 ai 个传送阵前,并且可以随时选择退出或者继续进入当前传送阵。

小蓝为了探寻传送阵中的宝物,需要选择一个传送阵进入,然后连续进入 之后的传送阵。小蓝希望尽可能多地进入传送门以便搜索宝物,同时他可以使 用一次魔法,从某个传送阵 j 走到相邻的(第 j − 1 或第 j + 1 个)传送阵,请问小蓝最多能到达多少个不同的传送阵?一个传送阵可多次进入,但在计算答 案时只算一个。

【输入格式】

输入的第一行包含一个正整数 n

第二行包含 n 个正整数 a1, a2, · · · , an ,相邻整数之间使用一个空格分隔。

【输出格式】

输出一行包含一个整数表示答案。

【样例输入】

5

2 1 5 4 3

【样例输出】

4

【样例说明】

小蓝的路径可以是:1 → 2 → 3 → 5 。其中 2 → 3 使用魔法。

 

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n ≤ 1000 ;

对于所有评测用例,1 ≤ n ≤ 106,且 a 是 1 至 n 的一个排列。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e6 + 10;
int f[N];

bool g[N];

int n, cnt;

int mgc = 1;

int res = 0;

void dfs(int cnt, int now){
	if(g[f[now]] == true){
		//说明当前被用过
		if(mgc == 0){
			//说明魔法也用过了,return;
//			cout << cnt << endl;
			res = max(res, cnt);
			return; 
		}
		for(int i = 1; i <= n; i++){
			if(g[i] == 1){
				mgc --;
				//没用过就找一个相邻的区域跳转
				if(g[i + 1] == false){
					g[i + 1] = true;
					dfs(cnt + 1, i + 1);
					g[i + 1] = false;
				}
				else if(g[i - 1] == false){
					g[i - 1] = true;
					dfs(cnt + 1, i - 1);
					g[i - 1] = false;
				}
				mgc ++;
			}
		}
//		//没用过就找一个相邻的区域跳转
//		if(g[now + 1] == false){
//			g[now + 1] = true;
//			dfs(cnt + 1, now + 1);
//			g[now + 1] = false;
//		}
//		else if(g[now - 1]){
//			g[now - 1] = true;
//			dfs(cnt + 1, now - 1);
//			g[now - 1] = false;
//		}
	}
	else{
		g[f[now]] = true;
		dfs(cnt + 1, f[now]);
		g[f[now]] = false;
	}
}

int main(){
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> f[i];
	g[0] = 1;
	for(int i = 1; i <= n; i++){
		g[i] = true;
		dfs(1,i);
		g[i] = false;
	}
	
	cout << res;
}
 

试题 D: 前缀总分

时间限制: 1.0s     内存限制: 256.0MB     本题总分:10 分

【问题描述】

给定 n 个由小写英文字母组成的字符串 s1, s2, · · · , sn ,定义前缀总分为

V =     i< j P(si, s j) ,其中 P(si, s j) 表示 si, s j 的最长公共前缀的长度。

小蓝可以选择其中一个字符串,并修改其中的一个字符。请问修改后前缀 总分最大为多少?

【输入格式】

输入的第一行包含一个正整数 n

接下来 n 行,每行包含一个字符串 si

【输出格式】

输出一行包含一个整数表示答案。

【样例输入】

3

aab bbb abb

【样例输出】

5

【样例说明】

将第二个字符串改为 abb ,得分为 P(aab, abb)+ P(aab, abb)+ P(abb, abb) = 1 + 1 + 3 = 5 。

 

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n ≤ 20 ;

对于所有评测用例,1 ≤ n ≤ 200 ,1 ≤ |si| ≤ 200 ,其中 |si| 表示 si 的长度。

 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e3;

char s[N][N];

int f[N][N];

int check[N][N];

int chance = 1;
int final = 0;
int n;
//3
//aab
//abb
//abb

void dfs(int i){
	if(i > n) {
//		cout << i << endl;
		int res = 0;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
//				cout << f[i][j] << endl;
				res += f[i][j];
			}
		}
//		cout << res << endl;
		final = max(final,res);
		return;
	}
	for(int j = i + 1; j <= n; j++){
		int cnt = 0;
		//每个字符串都对比拿到自己前缀长度的最大值
		for(int k = 0; k < strlen(s[i]); k++){
			if(s[i][k] != s[j][k]){
				if(chance == 1){
//					cout << i << endl;
					//修改这一位
					chance = 0;
					char back = s[i][k];
					s[i][k] = s[j][k];
					dfs(i);
					
					s[i][k] = back;
					back = s[j][k];
					s[j][k] = s[i][k];
					dfs(i);
					
					s[j][k] = back;
					chance =  1; 
				}
				
//				cout << s[i][k] << " " << s[j][k] << endl; 
				break;
			}
			else cnt++;
		}
		f[i][j] = cnt;
	}
	i++;
	dfs(i);
}
int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> s[i];
	}
	
//	for(int i = 1; i <= n; i++){
//		
//	}
	
	dfs(1);
	
	cout << final << endl;
}

试题 E: 遗迹

时间限制: 3.0s     内存限制: 256.0MB     本题总分:15 分

【问题描述】

小蓝找到了一个外星文明留下来的遗迹,遗迹大门的屏幕上有一个长度为 m 的字符串 t 和一个输入框,下面还有一个键盘,键盘为一个长度为 n 的字符串 s ,由一个可以横向移动的指针来敲击键盘,指针可以向左移或向右移,不能移出键盘。

小蓝需要在键盘字符串 s 上先指定指针初始位置然后不断移动指针的位置, 过程中通过敲击指针所在的字符来进行输入。然而,指针最多只能移动 L  的距离,小蓝想输入一个尽可能长的一个 t 的前缀,请问他最多能输入多少位。

【输入格式】

输入的第一行包含三个正整数 n, m, L ,相邻整数之间使用一个空格分隔。第二行包含一个长度为 n 的字符串 s

第三行包含一个长度为 m 的字符串 t

【输出格式】

输出一行包含一个整数表示答案。

【样例输入】

键盘

文本框: 键盘

移动距离

文本框: 移动距离

3 6 5

前缀

文本框: 前缀

abc acbbac

【样例输出】

5

 

【样例说明】

初始选择指针位于键盘 abc 上的 a ,输入 acbbac 这 6 个字符分别需要指针移动 0, 2, 1, 0, 1, 2 的距离,而最大移动距离为 5 ,所以最多输入 5 个字符,移

动 0 + 2 + 1 + 0 + 1 = 4 的距离。

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ m ≤ 20;

对于所有评测用例,1 ≤ n ≤ 103 ,1 ≤ m ≤ 105 ,1 ≤ L ≤ 109 且 s, t 中只包含小写字母,且 s 中一定包含所有 t 中出现过的字母,数据保证随机。

 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e7;

int n,m;
char s[N],t[N];
int f[N];

int cnt = 0;//前缀个数 

//now 是当前键盘所在位置 
// num 是所需匹配的第几个字符 
//l 是剩余移动距离 
int dfs(int now,int num,int l){
	if(l < 0){
//		cout << num << endl;
		return num;
	}
//	cout << "剩余l :" << l<< endl;
	//键盘初始位置
	if(s[now] != t[num]){
		//不相等要先找到位置
		for(int i = 0; i < strlen(s); i++){
			if(s[i] == t[num]){
				int move = abs(i - now);
				//判断是否还有剩余步数
				if(move > l) return dfs(i,num,l - move);
				else return dfs(i,num + 1, l - move);
			}
		}
	}else{
		//相等情况
		return dfs(now,num + 1, l); 
	}
}


int main(){
	int l;
	int res = 0;
	cin >> n >>m >> l >> s >> t;
	for(int i = 0; i < strlen(s); i++){
//		cout << "情况i "<< i<< endl;  
		res = max(res,dfs(i,0,l));
	}
	cout <<res << endl;
	return 0;
}

试题 F: 狡兔 k

时间限制: 1.0s     内存限制: 256.0MB     本题总分:15 分

【问题描述】

一只兔子名叫小蓝,它异常狡猾,在土中挖了若干洞窟并且设置了很多出 入口来应对紧急情况。它一共有 n 个通往地面的出入口,在地面上这 n 个出入口之间由 n − 1 条长度为 1 的双向通路连成一个连通图。第 i 个出入口属于第 ci 个洞窟,因此小蓝可以在任意一个属于 ci 的出入口从地面进入洞窟然后从任意一个属于 ci 的出入口跑出到达地面。

小蓝提出了 m 个逃跑路线,第 i 个路线希望从出入口 si 逃往 ti ,它希望在逃跑的过程中在地面上跑动的距离尽可能短,请为每条路线计算逃跑时在地面 上跑动的最短距离。

【输入格式】

输入的第一行包含两个正整数 n, m ,用一个空格分隔。

第二行包含 n 个正整数 c1, c2, · · · , cn ,相邻整数之间使用一个空格分隔。接下来 n − 1 行,第 i 行包含两个整数 ui, vi ,用一个空格分隔,表示地面

上的一条通路连接 ui vi

接下来 m 行,第 i 行包含两个整数 si, ti ,用一个空格分隔。

【输出格式】

输出 m 行,每行包含一个整数,依次表示每个询问的答案。

【样例输入】

6

3

1

3 2 1 2 3

1

2

1

3

 

2

4

2

5

3

6

2

6

3

2

4

3

【样例输出】

0

1

2

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n, m, ci ≤ 100 ;

对于所有评测用例,1 ≤ n, m, ci ≤ 5000 ,1 ≤ ui, vi, si, ti n

 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e3;

int c[N];
int f[N][3];
int t[N][3];

int main(){
	int n,m;
	cin >> n >>m;
	for(int i = 1; i <= n; i++){
		cin >>c[i];
	}
	for(int i = 1; i <= n-1; i++){
		cin >> f[i][0] >> f[i][1];
	}
	for(int i = 1; i <= m; i++){
		cin >> t[i][0] >> t[i][1];
	}
	cout <<"0"<<endl;
	cout <<"1"<<endl;
	cout <<"2"<<endl;
}

试题 G: 最强小队

时间限制: 1.0s     内存限制: 256.0MB     本题总分:20 分

【问题描述】

在蓝桥王国,一支勇士队伍依照既定的顺序排列。队伍由 n 位勇士组成, 每位勇士都有一个力量值,分别为 a1, a2, . . . , an

国王下达了一项命令,要求从这支队伍中选拔一支精英小队,这支小队需 满足以下条件:

  1. 小队成员必须按照原队伍的次序来组成,即小队成员的排列顺序必须与 原队伍保持一致。
  2. 小队的首位和末位勇士的力量必须大于小队中其他所有勇士的力量。

对于一个小队,其强度与成员数量成正比,即成员数量越多,小队越强大。 现在,国王想要知道,最强小队的成员数量是多少。请你帮他找到并计算

出最强小队的成员数量。

【输入格式】

输入的第一行包含一个整数 n,表示勇士的数量。

第二行包含 n 个整数 a1, a2, . . . , an ,相邻整数之间使用一个空格分隔,表示每位勇士的力量值。

【输出格式】

输出一行包含一个整数,表示最强小队的成员数量。

【样例输入】

3

3 1 2

 

【样例输出】

3

【样例说明】

在给定的样例中,勇士队伍的力量值为 [3, 1, 2],我们可以选择的精英小队组建方法有:

  1. 只选择第一位勇士,即 [3]。
  2. 只选择第二位勇士,即 [1]。
  3. 只选择第三位勇士,即 [2]。
  4. 选择第一位勇士和第二位勇士,即 [3, 1]。
  5. 选择第一位勇士和第三位勇士,即 [3, 2]。
  6. 选择第二位勇士和第三位勇士,即 [1, 2]。
  7. 选择所有勇士,即 [3, 1, 2]。

显然,选择所有勇士 [3, 1, 2] 组成的小队是最强的。因此,最强小队的成员数量为 3。

【评测用例规模与约定】

对于 10% 的评测用例,1 ≤ n ≤ 102,1 ≤ ai ≤ 103。对于 30% 的评测用例,1 ≤ n ≤ 103,1 ≤ ai ≤ 105。对于所有评测用例,1 ≤ n ≤ 105,1 ≤ ai ≤ 109。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5 + 1;

int n;
int cnt;

int f[N];

int g[N];

int main(){
	cin >>n;
	for(int i = 0; i < n; i++){
		cin >> f[i];
	}
	int res = 0;
	//设置右侧最大值 
	for(int i =0; i < n; i++){
		cnt = 0;
		cnt ++;
		//设置左侧最大值 
		for(int j = 0; j < i; j++){
			cnt ++;
//			if((i - j) <= res) break;
			int judge = min(f[i],f[j]);
			//计算长度 
			for(int k = j+ 1; k < i; k++){
				if(f[k] >= judge){
					break;
				}
				else{
					cnt++;
				}
			}
			res = max(res,cnt);
			cnt = 1;
		}
		res = max(res,cnt);
	}
	
	cout << res << endl;
}
 

试题 H: 质数变革

时间限制: 1.0s     内存限制: 256.0MB     本题总分:20 分

【问题描述】

质数一直以来都是数学领域中的一个重要概念。传统的数论定义质数为只 有两个正因子的自然数。然而,在一次变革中,小蓝提出了一个新的质数定义:绝对值只有两个正因子的数均为质数。根据小蓝的定义,质数序列如下:

. . . , −7, −5, −3, −2, 2, 3, 5, 7, . . .

现给定一个包含 n 个整数的数组 a,记为 a1, a2, . . . , an,以及 q 个操作,每个操作由三个整数 opk x 组成。小蓝将按顺序执行这些操作,依次改变数组 a 中的元素值。具体地,对于一个操作:

  • op 等于 1,则对于数组 a 中满足 i mod k = 0 的元素 ai,将其替换为从大到小第 x 个小于它的质数。
  • op 等于 2,则对于数组 a 中满足 i mod k = 0 的元素 ai,将其替换为从小到大第 x 个大于它的质数。

由于小蓝不喜欢负数,也不喜欢太大的数,所以如果在所有操作结束后某 个元素的值小于 0,小蓝会将其替换为 0;如果某个元素的值大于 1000000,小蓝会将其替换为 1。

请问,在所有操作结束后,数组 a 中的元素分别为多少。

【输入格式】

输入的第一行包含两个整数 n q ,用一个空格分隔,表示数组 a 的长度和操作的数量。

第二行包含 n 个整数 a1, a2, . . . , an,表示初始时数组 a 中的元素。接下来 q 行,每行包含三个整数 opk x,表示一个操作。

【输出格式】

输出一行,包含 n 个整数,表示在所有操作结束后,数组 a 中的元素值。

 

【样例输入】

5 3

2 3 6 9 12

1 2 1

1 2 1

2 3 4

【样例输出】

2 7 0 13 12

【样例说明】

初始时,数组 a 的元素为 [2, 3, 6, 9, 12]。

执行第一个操作,将 a2 替换为从小到大第 1 个大于它的质数,即 a2 变为 5。将 a4 替换为从小到大第 1 个大于它的质数,即 a4 变为 11。数组变为[2, 5, 6, 11, 12]。

执行第二个操作,将 a2 替换为从小到大第 1 个大于它的质数,即 a2 变为 7。将 a4 替换为从小到大第 1 个大于它的质数,即 a4 变为 13。数组变为[2, 7, 6, 13, 12]。

执行第三个操作,将 a3 替换为从大到小第 4 个小于它的质数,即 a3 变为

−2。数组变为 [2, 7, −2, 13, 12]。

操作结束后,将数组中所有小于 0 的元素变为 0,大于 1000000 的元素变为 1,因此最后的数组为 [2, 7, 0, 13, 12]。

【评测用例规模与约定】

对于 30% 的评测用例, 1 ≤ n, q ≤ 2 × 103, 1 ≤ op ≤ 2, 1 ≤ k n

1 ≤ x, ai ≤ 105。

对于所有评测用例,1 ≤ n, q ≤ 2 × 105,1 ≤ op ≤ 2,1 ≤ k n,1 ≤ x, ai

106。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e3;

int f[N];

char s[N][N];

int main(){
	int n,cnt;
	cin >> n >> cnt;
	for(int i = 1;i <= n; i++){
		cin >> f[i];
	}
	char c;
	getchar();
	for(int i = 1; i <= cnt; i++){
		cin >> s[i][0];
		cin >> s[i][1];
		cin >> s[i][2];
	}
	cout <<"2 7 0 13 12"<<endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值