攀拓计算机能力测评-程序设计-2023年冬季考试 - 乙级答案

B-1 能不能整除

    有无穷多正整数 n 可以整除 2n−2,我们称这样的 n 是“能整除”的数。本题就请你找出给定区间内所有能整除的数。
    注:a 可以整除 b 是指 b/a 是一个整数。

输入格式:

    输入在一行中给出两个正整数 a 和 b(1≤a≤b≤60),数字间以空格分隔。

输出格式:

    按递增序输出闭区间 [a,b] 内“能整除”的数,每个数字占一行。但如果一个都没有,则在一行中输出 No Solution

输入样例 1:

15 20

输出样例 1:

17
19

输入样例 2:

8 10

输出样例 2:

No Solution

AC代码:

    本题注意需要使用(long long)来确保精度问题。

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

int main()
{
	int a, b;
	cin >> a >> b;
	int flag = 1;
	for(int i = a; i <= b; i++)
	{
		if(((long long)pow(2, i) - 2) % i == 0){
			flag = 0;
			cout << i << endl;
		}
	}
	if(flag){
		cout << "No Solution";
	}
	return 0;
}

B-2 人类的本质

    本题借鉴了知乎用户的一篇文章《人类的本质就是复读机》。文中说“众所周知,人类的本质就是复读机,而且是劣质复读机。”因为“当看到大人说了‘狗’,‘猫’,‘花猫’后,你能对类似的情形使用‘花狗’,这便是劣质复读。”即“我们通过复读格式而不仅仅是内容,来处理要复读无限个对象的困难。”
    本题就请你写程序模仿这个劣质复读的行为:

  • 当大人说出一个字时,你只需要简单复读这个字,不需要记住任何内容;
  • 当大人说出连续的多个字,而此时你脑子里没有记住任何字时,你首先简单地复读这些字,同时记住第一个字;
  • 当大人说出连续的多个字,而此时你脑子里记忆了一个字时,你要把记住的那个字写在最前面,然后复读大人说出的这些字;同时把脑子里记住的字更新为当前大人说的第一个字。

    看看这样做是否能让我们“表现得像个能思考的人”。

输入格式:

    输入第一行首先给出一个正整数 n (≤100),是大人说出的句子数量。随后 n 行,每行给出一句话。
    “一句话”由不超过 10 个“字”组成。每个“字”是仅由小写英文字母组成的、长度不超过 8 个字母的字符串。相邻两个“字”之间用 1 个空格分隔,行首位没有多余空格。每行以一个回车结束。

输出格式:

    对大人给出的每个句子,按照劣质复读机的规则给出你的输出。每个句子占一行,相邻两个“字”之间用 1 个空格分隔,行首位没有多余空格。

输入样例:

6
mao
hua mao
gou
tu gou
da sha gua
da sha gua

输出样例:

mao
hua mao
gou
hua tu gou
tu da sha gua
da da sha gua

AC代码:

isSpace方法主要用来捕获空格字符(' ')的存在,然后用于分类讨论。

    情况一:如果没有空格字符,说明就一个单词,直接输出即可。

    情况二:如果有空格字符,说明有多个单词,此时检查vector中是否存在上一次的“记忆”,如果存在则先输出记忆,不存在则直接输出字符串;如果不存在则直接输出字符串,并把当前字符串的第一个单词保存为“记忆”。

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

int isSpace(string s);

int main()
{
	int n;
	cin >> n;
	getchar();
	vector<string> v;
	for(int i = 0; i < n; i++){
		string speak;
		getline(cin, speak);
		if(!isSpace(speak)){
			cout << speak << endl;
		}else{
			if(v.empty()){
				stringstream ss;
				for(int j = 0; j < speak.length(); j++){
					if(speak[j] != ' '){
						ss << speak[j];
					}else if(speak[j] == ' '){
						ss << speak[j];
						break; 
					}
				}
				v.push_back(ss.str());
				cout << speak << endl;
			}else{
				stringstream ss;
				for(int j = 0; j < speak.length(); j++){
					if(speak[j] != ' '){
						ss << speak[j];
					}else if(speak[j] == ' '){
						ss << speak[j];
						break;
					}
				}
				cout << v[0];
				v.erase(v.begin(), v.end());
				v.push_back(ss.str());
				cout << speak << endl;
			}
		}
	}
	return 0;
}

int isSpace(string s)
{
	for(int i = 0; i < s.length(); i++){
		if(s[i] == ' '){
			return 1;
		}
	}
	return 0;
}

B-3 开车还是地铁

    杭州承办了 2022 亚运会。为缓解亚运时的交通压力,杭州市政府决定在 2023 年 9 月 18 日至 10 月 9 日期间实行特殊的限行规定,对所有浙 A 小客车实行“单双号通行”,其中“单双号通行”规则为:按机动车号牌最后一位阿拉伯数字,实行“单日单号、双日双号”通行(单号为1、3、5、7、9;双号为2、4、6、8、0)。例如 9 月 23 日,车牌为浙A 12345 的小客车允许通行,而浙A 1234Q 的小客车则不允许通行。

    而在 2023 年的其他日子里,杭州实行“工作日错峰出行”的限行措施,即:按机动车号牌最后一位阿拉伯数字,周一尾号 1 和 9 禁行,周二尾号 2 和 8 禁行,周三尾号 3 和 7 禁行,周四尾号 4 和 6 禁行,周五尾号 5 和 0 禁行的规则,周六日不限行。

    现在给定你若干个 5 位的机动车号牌以及对应的出行日期,请你判断该号牌在出行日期是否限行。

输入格式:

    输入第一行是一个正整数 N (1≤N≤50),表示有 N 个询问。

    接下来的 N 行,每行首先是两个正整数 M 和 D,表示日期为 2023 年 M 月 D 日。然后是一个 5 位的车牌号码,保证车牌号码一定至少含有一个阿拉伯数字,并且只含有大写字母和数字,且日期一定合法。

    已知 2023 年 1 月 1 日是周日。为方便起见,不考虑放假等特殊情况。

输出格式:

    对于每个询问,如果车牌在出行日期禁行,则输出 Yes,否则输出 No。

输入样例:

5
9 17 12345
9 18 12345
9 19 12345
2 28 2QQQQ
12 31 4A23B

输出样例:

No
Yes
No
Yes
No

AC代码:

注意:禁行输出“Yes”,否则输出“No”

    首先使用getMonthDays()获取到2023年每个月多少天。然后根据2023年1月1日是周日(已知)进行推算,使用getWeekofDays()获取到周几,然后使用getlastNum()获取车牌的最后一位数字,进行相应的条件判断即可。

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

int getMonthDays(int month);
int getWeekofDays(int month, int day);
int getlastNum(string id);

int main()
{
	int N;
	cin >> N;
	for(int i = 0; i < N; i++)
	{
		int months, days;
		string car;
		cin >> months >> days >> car;
		int day = getWeekofDays(months, days);
		if((months == 9 && days >= 18 && days <= 30) || (months == 10 && days >= 1 && days <= 9)){
			if(days % 2 == 0){
				if(getlastNum(car) % 2 == 0){
					cout << "No" << endl;
				}else{
					cout << "Yes" << endl;
				}
			}else{
				if(getlastNum(car) % 2 != 0){
					cout << "No" << endl;
				}else{
					cout << "Yes" << endl;
				}
			}
		}else{
			if(day == 1){
				if(getlastNum(car) == 1 || getlastNum(car) == 9){
					cout << "Yes" << endl;
				}else{
					cout << "No" << endl;
				}
			}else if(day == 2){
				if(getlastNum(car) == 2 || getlastNum(car) == 8){
					cout << "Yes" << endl;
				}else{
					cout << "No" << endl;
				}
			}else if(day == 3){
				if(getlastNum(car) == 3 || getlastNum(car) == 7){
					cout << "Yes" << endl;
				}else{
					cout << "No" << endl;
				}
			}else if(day == 4){
				if(getlastNum(car) == 4 || getlastNum(car) == 6){
					cout << "Yes" << endl;
				}else{
					cout << "No" << endl;
				}
			}else if(day == 5){
				if(getlastNum(car) == 5 || getlastNum(car) == 0){
					cout << "Yes" << endl;
				}else{
					cout << "No" << endl;
				}
			}else{
				cout << "No" << endl;
			}
		}
	}
	return 0;
}

int getMonthDays(int month)
{
	switch(month){
		case 1:
			return 31;
		case 2:
			return 28;
		case 3:
			return 31;
		case 4:
			return 30;
		case 5:
			return 31;
		case 6:
			return 30;
		case 7:
			return 31;
		case 8:
			return 31;
		case 9:
			return 30;
		case 10:
			return 31;
		case 11:
			return 30;
		case 12:
			return 31;
	}
}

int getWeekofDays(int month, int day)
{
	int sumDay = 7;
	for(int i = 1; i < month; i++){
		sumDay += getMonthDays(i);
	}
	for(int i = 1; i < day; i++){
		sumDay++;
	}
	return (sumDay % 7 == 0 ? 7 : (sumDay % 7));
}

int getlastNum(string id)
{
	for(int i = id.length() - 1; i >= 0; i--)
	{
		if(id[i] >= '0' && id[i] <= '9'){
			return id[i] - '0';
		}
	}
	return -1;
}

B-4 方格填数

    2014 年哈佛-麻省理工数学竞赛中一道题是这样的:将正整数 1, 2, ..., 64 填入 8×8 的方格棋盘中,使得对任何 1≤i<64,i 和 i+1 都必须填在两个具有公共边的方格中。求棋盘上对角线中所填数的和的最大值。(注意:两个对角线都要考虑;64 和1 也必须填在两个具有公共边的方格中。)
这题有点难…… 幸好我们并不要求你写程序解决这个问题。
你的任务是:对任一给定的数字填充方案,判定其是否满足填充的条件,并且在所有给出的方案中,找出满足条件的、且对角线数字和最大的那个方案。

输入格式:

    输入在一行中首先给出两个正整数 n(≤100) 和 m(≤20),分别为棋盘的规模(即棋盘有 n×n 个方格)和输入的方案数量。因为容易证明奇数 n 一定不存在满足条件的解,所以题目保证给出的 n 都是偶数。
    随后给出 m 个填充方案,每个方案占 n 行,每行 n 个不超过 n2 的数字。同行数字间以空格分隔。

输出格式:

    在一行中首先输出满足条件的、且对角线数字和最大的方案数。随后一行中按照递增序输出这些方案的编号(编号按输入的顺序从 1 到 m)。
    注意每行数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

4 5
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 6
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 10
15 16 1 2
14 13 4 3
11 12 5 6
10 9 8 7
3 4 5 6
2 13 12 7
1 14 11 8
16 15 10 9
10 5 4 3
7 12 13 2
8 11 14 1
9 6 15 16

输出样例:

2
1 4

AC代码:

    judge()函数模拟判断 i 和 i+1的关系(不要忘记最后n^2和1的那一次)。sumValue()函数计算对角线的值,将所有模拟通过的值放入一个map集合中,键为index序列号,值为对角线的值,并在放的过程中捕捉最大对角线的值,而后使用迭代器遍历map,输出满足最大值的序列号即可。

    注意:当没有条件满足即 cnt = 0 时,而后一行的输出还要存在,即最后要写成(cout << res << endl;)√ ,不能写成(cout << res)要不然会出现测试点2格式错误

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

map<int, int> mp;

int judge(int n, int matrix[150][150]);
int sumValue(int n, int matrix[150][150]);

int main()
{
    int n, m;
    cin >> n >> m;
    int maxValue = 0;
    for(int i = 0; i < m; i++)
    {
    	int matrix[150][150];
        for(int j = 0; j < n; j++){
            for(int k = 0; k < n; k++){
                cin >> matrix[j][k];
            }
        }
        if(judge(n, matrix)){
            int value = sumValue(n, matrix);
            if(value > maxValue){
                maxValue = value;
            }
            mp[i + 1] = value;
        }
    }
    int cnt = 0;
    int flag = 0;
    stringstream ss;
    for(map<int, int>::iterator it = mp.begin(); it != mp.end(); it++)
    {
        if(it->second == maxValue){
            if(cnt){
                ss << " ";
            }
            ss << it->first;
            cnt++;
        }
    }
    cout << cnt << endl;
    string res = ss.str();
	cout << res << endl;
    return 0;
}

int judge(int n, int matrix[150][150])
{
    int x, y;
    int flag = 1;
    for(int i = 0; i < n && flag; i++)
    {
        for(int j = 0; j < n && flag; j++)
        {
            if(matrix[i][j] == 1){
                x = i;
                y = j;
                flag = 0;
            }
        }
    }
    if(flag){
        return 0;
    }
    int cnt = 2;
    while(cnt <= n * n){
        int able = 0;
        if(x - 1 >= 0 && matrix[x - 1][y] == cnt){
            able = 1;
            x = x - 1;
            cnt++;
        }else if(x + 1 < n && matrix[x + 1][y] == cnt){
            able = 1;
            x = x + 1;
            cnt++;
        }else if(y - 1 >= 0 && matrix[x][y - 1] == cnt){
            able = 1;
            y = y - 1;
            cnt++;
        }else if(y + 1 < n && matrix[x][y + 1] == cnt){
            able = 1;
            y = y + 1;
            cnt++;
        }
        if(!able){
            return 0;
        }
    }
    if((x - 1 >= 0 && matrix[x - 1][y] == 1) || (x + 1 < n && matrix[x + 1][y] == 1) || (y - 1 >= 0 && matrix[x][y - 1] == 1) || (y + 1 < n && matrix[x][y + 1] == 1)){
    	return 1;
	}else{
		return 0;
	}
}

int sumValue(int n, int matrix[150][150])
{
    int sum = 0;
    for(int i = 0; i < n; i++){
        sum += matrix[i][i];
    }
    for(int i = n - 1; i >= 0; i--){
        sum += matrix[(n - 1) - i][i];
    }
    return sum;
}

B-5 堆栈中的最大值

    堆栈是一种后进先出的线性结构。本题要求你在实现普通堆栈的进栈(Push)和出栈(Pop)功能时,外加一个查看最大值(PeekMax)的功能。重点是,这个额外的功能不能影响整个堆栈的操作效率。

输入格式:

    输入第一行首先给出一个正整数 n (≤105),是堆栈操作的数量。随后 n 行,每行给出一个操作,格式为:

  • Push X 表示将值为 X 的元素入栈,其中 X 是绝对值不超过 230 的整数;
  • Pop 表示将栈顶元素出栈;
  • PeekMax 表示要求返回此刻堆栈中最大元素的值。

输出格式:

    对输入中的每个操作,按照要求执行操作。对每个 Pop,在一行中输出出栈的元素值;对每个 PeekMax,在一行中输出此刻堆栈中最大元素的值。若执行 PopPeekMax 时堆栈是空的,则对应输出 ERROR,并且不执行该操作。
题目保证至少有一行输出。

输入样例:

11
Pop
Push 34
Push 28
PeekMax
Push 84
PeekMax
Pop
PeekMax
Pop
Pop
PeekMax

输出样例:

ERROR
34
84
84
34
28
34
ERROR

AC代码:

    核心思想:使用map集合的“键”记录当前的最大值,“值”记录当前最大值存在于堆栈的次数,当次数为0时使用erase方法删除,否则对应次数自减1即可。

    亲测有效,不会超时!

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

stack<long long> st;
map<long long, int> mp;

int main()
{
	int n;
	cin >> n;
	for(int i = 0; i < n; i++)
	{
		string s;
		cin >> s;
		if(s == "Push"){
			long long num;
			cin >> num;
			st.push(num);
			if(mp.find(num) == mp.end()){
				mp[num] = 1;
			}else{
				mp[num]++;
			}
		}else if(s == "Pop"){
			if(st.empty()){
				cout << "ERROR" << endl;
			}else{
				cout << st.top() << endl;
				if(mp[st.top()] - 1 == 0){
					mp.erase(st.top());
				}else{
					mp[st.top()]--;
				}
				st.pop();
			}
		}else if(s == "PeekMax"){
			if(st.empty()){
				cout << "ERROR" << endl;
			}else{
				map<long long, int>::reverse_iterator rit = mp.rbegin();
				cout << rit->first << endl;
			} 
		}
	}
	return 0;
}
  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值