2019秋季PAT甲级考试总结:努力+策略+运气

鉴于这两天有很多网友联系我问这次考试的题解,所以我干脆就花点时间把C++题解整理出来了,见文末


经过一两个月的备战PAT,在今天终于画上了一个圆满的句号,取得了满分的成绩。

我是在南京的金陵科技学院考试的,三个月前就报好了名,256元报名费。考试时间是从下午13:30-16:30,共四个题目,分别是20分,25分,25分,30分。考试环境是线上考试,在PAT的桌面客户端提交代码,其实就是和https://pintia.cn网站的页面一样。编程环境Java是eclipse,C++是Dev和codeblocks。我选择使用codeblocks。打开codeblocks的第一件事就是开启C++11的编译选项,然后测试下C++11是否可以正常运行。之后就开始做题了。

看到第一题时,算是道数学题,我看了十分钟,发现没看懂,顿时心里是有点慌的,然后我就决定先去看后面的题吧。

第二题是个链表题,这种题我之前做过很多次,所以我一眼就觉得我能做出来,code十来分钟,把样例跑出来了,然后自己想了组例子,感觉代码没什么问题了,就提交了,一遍就AC了,呵呵,开森?。

紧接着看第三题,是个二叉树的后缀遍历,超简单啊,也是十来分钟就搞出来了,交了上去,又是一遍过?。 此时已经50分到手了,心情超级好,发现左右两边的男生还在做第一题,我的内心默默感慨自己的策略是对的,幸好没有死磕第一题。

我又开第四题了,是个Dijkstra算法的题,跟以往的有所不同,以前都是求最短路,这次是判断这个排列是否是一个dis数组。思考了一会,有思路,然后写了大半个小时,再调试调试,感觉写的没什么问题了,就交了,又是一遍就AC了,心情越来越好??

回过头来看第一题,此时离考试结束还剩一个半小时,时间绰绰有余,我看右边的男生第一题没做出来,在做第二题。我在草稿纸上推算第一题,算了一二十分钟,感觉有思路,可以下手写了,把样例跑出来了,交上去,就过了一组数据,还有三组数据没过,得了10分,此时总分已经有90分了呵呵。不过离考试结束还早得很,我觉得这道题还可以救一救,于是我又反复调试,但实在没发现什么问题。我看数据范围小,我就决定打印所有的数据范围看一看,说不定能一眼看出异样呢。果然,我看到当最后一位为9时,会增加一个9,这样结果就不对了,激动,感觉修改过来,让遍历的最后一位不能取9,再次提交,这次过了3组,得了17分。这时离考试结束就剩十分钟了,然而我没什么思路了,我不知道最后一组数据会错在哪儿了,我感觉代码很完美呀。我以为我这次就要定格在97分了,而且这个时候,PAT的服务器突然崩溃了,监考老师让我们先在本地调试,然后等服务器恢复了再提交,会给我们延时十五分钟,这个时候我就无聊的看了一下榜单排名(我居然到考试就剩十分钟才想起来去看榜单,也真是够蠢的了),我发现我的97分排116名,然在我前面的115个人都是100分,并列排第一名,也就是说,我只要这道题得了满分,我也就是100分跟他们并列第一名。我然后去看了下AC率,发现第一题果然是最难的,只有很少一部分人做出来。于是我就趁着服务器崩溃的时间继续看我的打印所有数据的结果,其实此时并不抱太大希望的,但当我看到一组数据中的n是由大到小输出时,我突然反应过来题目要求好像是要增序输出,为什么我的输出中会有降序,阔怕,我赶紧想看题目,可是服务器还没回复过来。于是我就先将降序改成了增序,然后等到服务器恢复了,我就赶紧再去看一遍题目,果然是增序输出n,其实这个坑很难找,因为绝大部分数据中,n只有一种,所以如果不打印所有的测试结果,根本发现不了n是降序的。当时我真是激动坏了,我感觉这里改过来应该就能AC了,可我提交时,发现时间已经截止了,不过监考老师说等着过会补时15分钟,这段时间真焦急,老师说可以交了,我就把这份最终代码交上去,发现前面还有1000多人等待评测,唉真是心累啊,等到还剩五百多等待评测的时候,突然网页又显示服务器异常了,然后提交页面就没有了。。。┭┮﹏┭┮我就问监考老师我提交到一半突然服务器异常了,我有没有交上去呢,要不要重新提交,然后老师说那你重新交一下吧,于是我就点进提交列表准备重新提交,发现我刚才居然已经提交上去了,并且显示得分20分,????,终于AC了,当时的心情真是开心到飞起。然后我就准备起身离开了,并且看了一下名次,是第一名,满分,监考老师在后面说了句满分啊,不容易。哈哈我笑了笑没说什么,不过内心已是特别激动。

本次考试的结果我很是满意。


本次考试结果归功于,努力+策略+运气

努力:
在考试前一个月里,我每天都在PAT网站上刷真题,每天都是刷2~6个小时,我不是很闲的哟,我现在已经在工作了,刷题的时间都是挤出来的。而且刷题也不是盲目,遇到不会的题会去找题解,会去总结,可以看我最近的博客,全都是PAT的题解。当然我只是觉得对我有价值的题解才会写到博客里,普通题解只上传到GitHub了。PAT甲级题库里共有155题,我做了一百多道题。在考前我还在复习这些我曾写过的题。我觉得难得题有:动态规划(背包部分),树状数组,平衡二叉树,我害怕考到这些。

策略:
一般情况下,20分的题都比较简单,但这次考试显然不是这样,我庆幸我没有死磕第一题,要不然这次就凉了。我是先做后面三道题的,非常顺利的做出了后三道题,然后再做第一道题,心态更好了,思路也更清晰了。

运气:
刚才说的我害怕的三种题,这次都没考到,如果考到了这三者我可能就不会这么顺利了。其次,多亏了最后服务器崩溃的补时十五分钟,要不然我没时间调试出我最后的bug拿到满分,所以补时对我来说影响是巨大的。虽然监考老师说往年也都是这样,但对我来说还算是运气好吧。

继续加油,再接再厉。当下定决心做一件事时,就要全力以赴!
2019秋季PAT甲级考试总结:努力+策略+运气_第1张图片

2019秋季PAT甲级考试总结:努力+策略+运气_第2张图片

感谢我的idol一博哥哥给我力量
2019秋季PAT甲级考试总结:努力+策略+运气_第3张图片


2019秋季PAT甲级考试题解

由于我是重新写的,不记得题目的样例了,下面的代码仅代表我的思路,也许跟我在考场提交的源代码不完全一致。等到PAT网站上录入了这次的赛题,我再测试提交下,否则不敢保证下面的代码一定能AC,我只是凭记忆来复现当时提交的代码。

A题

A的长度为k,A的位和为m,A+1的位和为n,gcd(m,n)是大于2的素数。
给定k,m,求符合条件的n, A,增序输出。
可以看出n = m - 9 * i + 1,i 可以取[2, k]。然后就进行恶心的枚举即可。

#include
using namespace std;
int k, m, n, len, sum, f = 0;
vector<int>out;
void dfs(int step){
	if(step >= len){
		if(sum == n){
			f = 1;
			cout << n << " ";
			for(auto i: out){
				cout << i;
			}
			for(int i = 1; i <= k-len; i++){
				cout << 9;
			}
			cout << endl;
		}
		return;
	}
	for(int i = 0; i <= 9; i++){
		if(step == 0 and i == 0)continue;// 最高位不能为0
		if(step == len-1 and i == 9)continue;// 关键。第len-1位不能为9,否则A末尾则超过了k-len个9
		out[step] = i;
		sum += i;
		dfs(step+1);
		sum -= i;
	}
}
int gcd(int a, int b){
	return b == 0 ? a : gcd(b, a % b);
}
bool prime(int n){
	if(n <= 2)return false;// 此处把2也直接返回false。
	for(int i = 2; i * i <= n; i++){
		if(n % i == 0)return false;
	}
	return true;
}
int main(){
	ios::sync_with_stdio(false);
	int T;
	cin >> T;
	for(int t = 1; t <= T; t++){
		cin >> k >> m;
		f = 0;
		cout << "Case " << t << endl;
		for(int i = k; i >= 2; i--){
			n = m - 9 * i + 1;
			if(prime(gcd(m, n))){// m,n的最大公约数为超过2的素数
				len = k - i;
				out.clear();
				out.resize(len);
				sum = 0;
				dfs(0);
			}
		}
		if(f == 0){
			cout << "No solution" << endl;
		}
	}
}

B题(25分)

给出两个链表,长链表的长度是短链表的至少两倍。将短链表翻转,然后每隔两个长链表元素后接一个短链表元素。

#include
using namespace std;
struct Node
{
	int addr, val, next;
};
int main(){
	int addr1, addr2, n;
	scanf("%d %d %d", &addr1, &addr2, &n);// 怕T,用scanf
	map<int, Node>M;
	for(int i = 0; i < n; i++){
		int addr, val, next;
		scanf("%d %d %d", &addr, &val, &next);
		M[addr] = {addr, val, next};
	}
	vector<Node>v1, v2, v3;// v1 v2表示两个链表,v3表示最后合并的结果链表
	int p = addr1;
	while(p != -1){
		v1.push_back(M[p]);
		p = M[p].next;
	}
	p = addr2;
	while(p != -1){
		v2.push_back(M[p]);
		p = M[p].next;
	}
	// 使用用v1表示更长的那个链表,v2表示短的链表
	if(v1.size() < 2*v2.size()){
		swap(v1, v2);
	}
	reverse(v2.begin(), v2.end());// 翻转短链表
	for(int i = 0; i < v2.size(); i++){
		// 直接模拟插入到一个新链表即可。这样操作最简单不容易错
		v3.push_back(v1[2*i]);
		v3.push_back(v1[2*i+1]);
		v3.push_back(v2[i]);
	}
	for(int i = 2*v2.size(); i < v1.size(); i++){
		v3.push_back(v1[i]);
	}
	cout << v3.size() << endl;// 这里要输出长度吗,我也不记得了。。
	for(int i = 0; i < v3.size()-1; i++){
		printf("%05d %d %05d\n", v3[i].addr, v3[i].val, v3[i].next);
	}
	printf("%05d %d -1\n", v3.back().addr, v3.back().val);
}

C题(25分)

赤裸裸的二叉树后序遍历问题

#include
using namespace std;
struct Node
{
	string op;
	int left, right;
};
map<int, Node>M;
string dfs(int root){
	if(M[root].left == -1 and M[root].right == -1){// 叶节点直接返回(a)这种形式
		return "(" + M[root].op + ")";
	}
	if(M[root].left == -1){// 没有左子树,只有右子树,则M[root].op是一个+-符号,这是一个一元运算符。返回(-a)这种形式
		return "(" + M[root].op + dfs(M[root].right) + ")";
	}
	return "(" + dfs(M[root].left) + dfs(M[root].right) + M[root].op + ")";
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n;
	cin >> n;
	vector<int>book(n+1);
	for(int i = 1; i <= n; i++){
		string op;
		int left, right;
		cin >> op >> left >> right;
		M[i] = {op, left, right};
		if(left != -1)book[left] = 1;
		if(right != -1)book[right] = 1;
	}
	int root = -1;
	for(int i = 1; i <= n; i++){
		if(book[i]==0){// 题目中有说明parenless的节点为根节点
			root = i;
			break;
		}
	}
	cout << dfs(root) << endl;
}

D题(30分)

判断给定的数组是否是Dijkstra算法贪心过程的选取顺序。

#include
using namespace std;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n, m;
	cin >> n >> m;
	vector<vector<int>>G(n+1);
	for(int i = 1; i <= n; i++){
		G[i].resize(n+1);
		for(int j = 1; j <= n; j++){
			if(i==j){
				G[i][j] = 0;
			}else{
				G[i][j] = INT_MAX/2;
			}
		}
	}
	for(int i = 1; i <= m; i++){
		int x, y, z;
		cin >> x >> y >> z;
		G[x][y] = min(G[x][y], z);
	}
	int q;
	cin >> q;
	while(q--){
		bool f = true;
		vector<int>v(n+1);
		for(int i = 1; i<= n; i++){
			cin >> v[i];
		}
		int source = v[1];
		vector<int>dis(n+1), book(n+1);
		for(int i = 1; i <= n; i++){
			dis[i] = G[source][i];
		}
		book[source] = 1;
		for(int i = 2; i < v.size(); i++){
			int p = -1, MIN = INT_MAX;
			for(int j = 1; j <= n; j++){
				if(book[j]==0 and dis[j] < MIN){
					MIN = dis[j];
					p = j;
				}
			}
			if(dis[v[i]] != MIN){// 核心部分
				f = false;
				cout << "No" << endl;
				break;
			}
			p = v[i];
			book[p] = 1;
			for(int j = 1; j <= n; j++){
				if(book[j] == 0 and dis[j] > dis[p] + G[p][j] ){
					dis[j] = dis[p] + G[p][j];
				}
			}
		}
		if(f){
			cout << "Yes" << endl;
		}
	}
}

你可能感兴趣的:(PAT,总结,题解)