PAT(乙级)2019年春季考试总结

快速导航

  • 题目
    • 7-1 大美数 (15分)
    • 7-2 矩阵行平移 (20分)
    • 7-3 岩洞施工 (20分)
    • 7-4 性感素数 (20分)
    • 7-5 校庆 (25分)
  • 总结

买了一份去年PAT乙级春季考试打算在25号考试前模拟考一次,成绩并不是太理想,这里贴上自己的代码和思路:

题目

7-1 大美数 (15分)

若正整数 N 可以整除它的 4 个不同正因数之和,则称这样的正整数为“大美数”。本题就要求你判断任一给定的正整数是否是“大美数”。

输入格式:
输入在第一行中给出正整数 K(≤10),随后一行给出 K 个待检测的、不超过 10​4的正整数。

输出格式:
对每个需要检测的数字,如果它是大美数就在一行中输出 Yes,否则输出 No。

输入样例:
3
18 29 40
输出样例:
Yes
No
Yes

分析:这题只拿到11分,最后两个测试点超时。思路是先将所有的因数放入一个数组中,然后嵌套四个for循环进行判断,能否相加然后整除。
这里发现了我数学知识上的一个漏洞:a整除b的意思是b % a == 0,而不是a % b == 0

#include 
#include 
#include 
using namespace std;
bool judge(int);
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int num;
		cin >> num;
		if (judge(num))
			cout << "Yes\n";
		else
			cout << "No\n";
	}
	return 0;
}
bool judge(int n)
{
	vector<int> vec;
	map<int, bool> mp;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (!mp[i] && !mp[j] && i * j == n)
			{
				vec.push_back(i);
				mp[i] = true;
				vec.push_back(j);
				mp[i] = true;
			}
		}
	}
	if (vec.size() < 4)
		return false;
	else
	{
		for (int i = 0; i < vec.size(); i++)
		{
			for (int j = i + 1; j < vec.size(); j++)
			{
				for (int k = j + 1; k < vec.size(); k++)
				{
					for (int m = k + 1; m < vec.size(); m++)
					{
						int num = vec[i] + vec[j] + vec[k] + vec[m];
						if (num % n == 0)
							return true;
						else continue;
					}
				}
			}
		}
	}
	return false;
}

后来网上查找答案发现我的judge函数可以优化一下,但是因为无法再提交了所以无法知道是否能ac,在此先贴出:

bool judge(int n)
{
	vector<int> vec;
	for (int i = 1; i <= (int)sqrt((double)n); i++)
	{
		if (n % i == 0)
		{
			vec.push_back(i);
			vec.push_back(n / i);
		}
	}
	if (vec.size() < 4)
		return false;
	else
	{
		for (int i = 0; i < vec.size(); i++)
		{
			for (int j = i + 1; j < vec.size(); j++)
			{
				for (int k = j + 1; k < vec.size(); k++)
				{
					for (int m = k + 1; m < vec.size(); m++)
					{
						int sum = vec[i] + vec[j] + vec[k] + vec[m];
						if (n % sum == 0)
							return true;
						else continue;
					}
				}
			}
		}
	}
	return false;
}

7-2 矩阵行平移 (20分)

给定一个 n×n 的整数矩阵。对任一给定的正整数 k

输入格式:
输入第一行给出 3 个正整数:n(<100)、k( 接下来 n 行,每行给出 n 个不超过 100 的正整数,为矩阵元素的值。数字间以空格分隔。

输出格式:
在一行中输出平移后第 1 到 n 列元素的和。数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:
7 2 99
11 87 23 67 20 75 89
37 94 27 91 63 50 11
44 38 50 26 40 26 24
73 85 63 28 62 18 68
15 83 27 97 88 25 43
23 78 98 20 30 81 99
77 36 48 59 25 34 22
输出样例:
529 481 479 263 417 342 343
样例解读

需要平移的是第 1、3、5、7 行。给定 k=2,应该将这三列顺次整体向右平移 1、2、1、2 位(如果有更多行,就应该按照 1、2、1、2、1、2 …… 这个规律顺次向右平移),左端的空位用 99 来填充。平移后的矩阵变成:
99 11 87 23 67 20 75
37 94 27 91 63 50 11
99 99 44 38 50 26 40
73 85 63 28 62 18 68
99 15 83 27 97 88 25
23 78 98 20 30 81 99
99 99 77 36 48 59 25

思路:这题一定要仔细读题,样例给的误导性很强,一度让我以为是这样:第一行平移1个、第三行平移k个、第五行平移1个、第七行平移k个…如果这样做测试点1236就都出错了。题目要求是1、……、k、1、……、k这样
举例:第一行平移1个、第三行平移2个、第五行平移3个…第2n+1行平移k个、第2n+3行平移1个,接着往后循环。

#include 
using namespace std;
int matrix[200][200];
int main()
{
	int n, k, x;
	cin >> n >> k >> x;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			cin >> matrix[i][j];  //数据存入二维数组
	int cnt = 0;
	for (int i = 0; i < n; i++)
	{
		if ((i + 1) & 1) //当遇到奇数行时
		{
			cnt++; //cnt自增,记录是第几个奇数行
			int d = cnt % k;
			if (!d) d = k; //如果d是0,说明cnt正好是k,要往右移k个
			for (int j = n - 1; j >= 0; j--)
				matrix[i][j + d] = matrix[i][j];
			for (int j = 0; j < d; j++)
				matrix[i][j] = x;
		}
		else
			continue;
	}
	vector<int> vec;
	for (int i = 0; i < n; i++)
	{
		int num = 0;
		for (int j = 0; j < n; j++)
			num += matrix[j][i];  //列累加,列不动,行动
		vec.push_back(num);
	}
	int flag = 0;
	for (int i = 0; i < vec.size(); i++)
	{
		if (flag != 0)
			cout << ' ';
		cout << vec[i];
		flag = 1;
	}
	return 0;
}

7-3 岩洞施工 (20分)

要将一条直径至少为 1 个单位的长管道水平送入地形复杂的岩洞中,究竟是否可能?下面的两幅图分别给出了岩洞的剖面图,深蓝色的折线勾勒出岩洞顶部和底部的轮廓。图 1 是有可能的,绿色部分显示直径为 1 的管道可以送入。图 2 就不可能,除非把顶部或底部的突出部分削掉 1 个单位的高度。
PAT(乙级)2019年春季考试总结_第1张图片
本题就请你编写程序,判断给定的岩洞中是否可以施工。

输入格式:
输入在第一行给出一个不超过 100 的正整数 N,即横向采样的点数。随后两行数据,从左到右顺次给出采样点的纵坐标:第 1 行是岩洞顶部的采样点,第 2 行是岩洞底部的采样点。这里假设坐标原点在左下角,每个纵坐标为不超过 1000 的非负整数。同行数字间以空格分隔。
题目保证输入数据是合理的,即岩洞底部的轮廓线不会与顶部轮廓线交叉。

输出格式:
如果可以直接施工,则在一行中输出 Yes 和可以送入的管道的最大直径;如果不行,则输出 No 和至少需要削掉的高度。答案和数字间以 1 个空格分隔。

输入样例 1:
11
7 6 5 5 6 5 4 5 5 4 4
3 2 2 2 2 3 3 2 1 2 3
输出样例 1:
Yes 1
输入样例 2:
11
7 6 5 5 6 5 4 5 5 4 4
3 2 2 2 3 4 3 2 1 2 3
输出样例 2:
No 1

思路:这题其实我只得了14分,有两个测试点没通过,但是通过率是5道题中最高的,然后百度别人的题解才发现是我想的太复杂了,只要找出顶端最低的点和底端最高的点,如果两个点之间有空隙则可以施工,最大直径即两点之差;如果没有空隙,则让底端最高点减去顶端最低点再加1即可,为什么这样做呢?假设底端最高点减顶端最低点得n,如果n是0说明两点持平,再加1即可得到一条隧道;如果大于0,减去n得0即可将两点持平,再加1就得到了一条隧道。

#include 
#include 
using namespace std;
int main()
{
	int n, min = 1001, max = 0;
	cin >> n;
	vector<int> top(n);
	vector<int> bottom(n);
	for (int i = 0; i < n; i++)
	{
		cin >> top[i];
		if (min > top[i])
			min = top[i];
	}
	for (int i = 0; i < n; i++)
	{
		cin >> bottom[i];
		if (max < bottom[i])
			max = bottom[i];
	}
	if (min - max > 0)
		cout << "Yes " << min - max;
	else
		cout << "No " << max - min + 1;
	return 0;
}

7-4 性感素数 (20分)

“性感素数”是指形如 (p, p+6) 这样的一对素数。之所以叫这个名字,是因为拉丁语管“六”叫“sex”(即英语的“性感”)
现给定一个整数,请你判断其是否为一个性感素数。

输入格式:
输入在一行中给出一个正整数 N (≤10​8)。

输出格式:
若 N 是一个性感素数,则在一行中输出 Yes,并在第二行输出与 N 配对的另一个性感素数(若这样的数不唯一,输出较小的那个)。若 N 不是性感素数,则在一行中输出 No,然后在第二行输出大于 N 的最小性感素数。

输入样例 1:
47
输出样例 1:
Yes
41
输入样例 2:
21
输出样例 2:
No
23

思路:这题考察素数判断,只要能写出判断素数的函数即可。

#include 
using namespace std;
bool isprime(int);
bool issex(int);
int main()
{
	int n, flag = 0;
	cin >> n;
	if (issex(n))
	{
		cout << "Yes\n";
		if (isprime(n - 6))  //要求先输出较小的那个,如果不是则输出大的那个
			cout << n - 6;
		else
			cout << n + 6;
		system("pause");
		return 0;
	}else
	{
		cout << "No\n";
		for (int i = n + 1; i >= 2; i++) //不停往前判断是否为性感素数
		{
			if (issex(i))
			{
				cout << i;
				break;
			}
		}
		return 0;
	}
	return 0;
}
bool issex(int n)
{
	if (isprime(n) && (isprime(n - 6) || isprime(n + 6)))
		return true;
	return false;
}
bool isprime(int n)
{
	if (n < 2)
		return false;
	for (int i = 2; i * i <= n; i++)
		if (n % i == 0)
			return false;
	return true;
}

7-5 校庆 (25分)

2019 年浙江大学将要庆祝成立 122 周年。为了准备校庆,校友会收集了所有校友的身份证号。现在需要请你编写程序,根据来参加校庆的所有人士的身份证号,统计来了多少校友。

输入格式:
输入在第一行给出不超过 10​5的正整数 N,随后 N 行,每行给出一位校友的身份证号(18 位由数字和大写字母X组成的字符串)。题目保证身份证号不重复。
随后给出前来参加校庆的所有人士的信息:首先是一个不超过 10​5的正整数 M,随后 M 行,每行给出一位人士的身份证号。题目保证身份证号不重复。
输出格式:
首先在第一行输出参加校庆的校友的人数。然后在第二行输出最年长的校友的身份证号 —— 注意身份证第 7-14 位给出的是 yyyymmdd 格式的生日。如果没有校友来,则在第二行输出最年长的来宾的身份证号。题目保证这样的校友或来宾必是唯一的。

输入样例:
5
372928196906118710
610481197806202213
440684198612150417
13072819571002001X
150702193604190912
6
530125197901260019
150702193604190912
220221196701020034
610481197806202213
440684198612150417
370205198709275042
输出样例:
3
150702193604190912

思路:这题并不是很难,但是刚开始还是粗心了,注意题目要求:如果有校友,则输出最年长的校友身份证号;如果没有,则输出参加校庆人士中最年长的身份证号。

#include 
#include 
using namespace std;
int main()
{
	int n, cnt = 0;
	cin >> n;
	map<string, bool> mp;
	for (int i = 0; i < n; i++) //将所有校友的身份证号列入散列表
	{
		string s1;
		cin >> s1;
		mp[s1] = true;
	}
	string oldguest = "99999999", old_sch = "99999999", ans1, ans2;
	int m, flag = 0;
	cin >> m;
	for (int i = 0; i < m; i++)
	{
		string s2;
		cin >> s2;
		string birth = s2.substr(6, 8); //birth表示每个身份证号的生日
		if (mp[s2])  //如果这个人是校友
		{
			cnt++; //计数
			if (birth < old_sch)  //如果此人更年长则执行if
			{
				flag = 1; //哨兵表示有校友
				old_sch = birth;
				ans1 = s2;
			}
		}else  //这人不是校友
		{
			if (birth < oldguest)
			{
				oldguest = birth;
				ans2 = s2;
			}
		}
	}
	cout << cnt << endl;
	if (flag) //flag等于1表示存在校友
		cout << ans1;
	else
		cout << ans2;
	return 0;
}

总结

这次考试并不尽如人意,pat乙级题库刷了两遍,平时对自己的要求是90分钟内写完5道题。但是这次写足了三个小时还没拿到满分,最后剩半小时的时候还有三题没有ac。自己最大的问题就是粗心,会忽略一些小细节,离考试还有4天,希望能如意拿到满分
PAT(乙级)2019年春季考试总结_第2张图片

你可能感兴趣的:(#,PAT乙级)