PAT甲级考纲:(官网目前已经删除了,以前是有的,见下文)
先说一下今天考试的整体情况:
因为这是第一次线上考试,导致很多地方包括很多同学的网络,设备等一系列问题,出了很多状况,导致很多考生被停止考试或者有的被禁赛三年。。。。
同考场真有一个大兄弟被禁赛三年了,原因是老师通过小程序喊他没回应,发消息也没回,于是老师果断给他禁赛了。。
正式考试前两天会有测试模拟,当时我的网络不稳定,导致第二机位gg了,然后老师提醒了我,到正式考试我花钱买流量,开热点来的,不过还好,全程第一机位+第二机位 2.5h 一共才用了100MB流量,结果我怕不够用,然后买了10G…!!!!
双机位小程序需要拍照,但是!!他的拍照算法用的不是手机自带相机算法,而是自创算法,成像能力极其差!几千万像素的手机拍出来都是糊的!!所以只能是把 脸+身份证+二维码堆在一块,手机贴脸照相,不然监考老师一直拒绝你登录,原因是照片不清晰。。。
本人第一次参赛,从过年就陆陆续续边复习考研,累了就玩一玩pat,慢慢整过来的,确实,备考只需要刷他的甲级题库就可以了。(强烈安利算法笔记上机实践那本书,按他的顺序分类练习,效果很棒!)
但是有一些是不需要刷的,比如
1026 Table Tennis
这个纯属超纲,是陈越版数据结构教材,整本书结尾篇的压轴题,感兴趣可以翻翻看
还有涉及动态规划,树状数组等题目都不会考(见下面考纲,放心除了考纲以内,其他部分绝对不会考!)
在达到乙级要求的基础上,还要求:
1· 具有充分的英文阅读理解能力;
2· 理解并掌握基础数据结构,包括:线性表、树、图;
3· 理解并熟练编程实现经典高级算法,包括哈希映射、并查集、最短路径、拓扑排序、关键路径、贪心、深度优先搜索、广度优先搜索、回溯剪枝等;
4· 具备较强的问题抽象和建模能力,能实现对复杂实际问题的模拟求解。
首先为什么我会把1加粗,实际上读题在甲级中占据很大一部分分数,试问读题都读不对,题目都理解错了,然后你的代码写的再完美也是答案错误
今天下午的考试,第二题,考完以后很多人都在考试群里(监考老师组织的群,考完以后没一会就解散了)说读不懂题目,根本没法做,样例都读不懂。然后陈老姥姥微博也有好多人留言说看不懂题目。
原因其实在于你的英语/理解力太差!太差!太差!
大多数人都觉得题目读不懂,是因为
The number must be the difference of the previous numbers
以上为回忆内容,具体真题还没有发布,但是原话差不多就是这样。
很多人都觉得difference是不同的意思,实际上这里的差值,也就是A-B的绝对值。所以,如果真的读不懂题目,直接gg了呀。也许本题或多或少可能有点描述偏差,但是利用标准测试案例+描述应该也可以理解!本次考试95人满分,满分人数比例和往届持平,从侧面说明说明题目并没有问题!
PAT 题目的题目我其实是刷了两遍,第一遍是个小白,啥都不会,边刷边学习,其中留下了很多测试点没过的情况,,筋疲力尽,就放下了。
之所以二刷是因为我的跨度比较大,后面都忘记了,然后我二刷的时候坚持做到:
1.所有题目自己完成,绝不会看任何一本书或者别人题解。
2.所有测试点出错自己改正,绝不看别人的分析
我觉的我之所以进步很快就是因为以上两点,其中最重要的是第二点,遇到测试点出问题,自己改就是了,当然我也有一点经验的:
遇到测试点出问题,首先最后几个那种测试花几十甚至上百毫秒的测试点绝地是一大堆数据,然后如果你前面的都过了,后面这种没过,那么你应该考虑数据的特殊性,比如:
1 是否存在两个数据相同即A=B的情况,然后你没考虑?
2.是否存在数据溢出,如int a*int b=long long?
3.以及涉及double数据是否存在先累加最后再算平均值减小误差而你是每次算平均值再相加导致数据精度损失?
4.题目隐含信息,一般比如,如果不告诉你所有输入是distinct(独一无二),那么极大可能就是某个测试点存在相同数值
等,当然上面肯定不是全部,需要你慢慢探索,慢慢学习,我曾经找一个题目的测试点分析了3个小时!!
但是正是我这种付出,培养了我自己找错误分析代码的能力!
此外,其实从1104往后每4个题就是一套真题,从2016年至今
(不信你可以买教育商城里面的真题然后做做看,对了,我还有几份多的教育超市真题,2016年,2019年都有,有需要做的同学可以私信我,我用不到了,我免费提供给你)
教育商城里面值得买的是2019年往后的题目,因为这些题目没有加入甲级练习题题库。
emm,写代码要坚持自己的原创,坚持深入理解背后的原理,只有真正理解了才可以自由发挥,自由创造。
实际上目前甲级题目涉及求最短路径的题目基本上都是Dijistra可以解决的,也就是没有负权值的情况,但是我还是建议亲爱的读者去学习一下
SPFA算法求最短路径,该算法不仅可以求正权值,也可以求负权值,而且比Dijistra写起来简单,也容易理解。
(我是考试前一天才看的,,,因为我怕今天的考试可能会出现求负权制的题目,但是学会了以后我觉得以前的题目都白写了,SPFA比Dijistra高效!而且方便理解,方便写!!)
emm,这大概是本人近期最后一贴了,开CSDN就是为了记录刷题过程,而后今天第一次参加PAT就拿满分弃坑了,很开心。
(开玩笑哈,我买了柳神的甲级和乙级题解呢,柳神也是我STL的引路人,算是半个师傅emm,当年我竟然用C语言最笨拙的方法刷题,而且还能刷好多道,好佩服傻傻的自己…)
传送门 ------->> 柳婼个人博客网站
------------------------------不优雅的分割线----------------------------------------
以下为本次考试我的源代码:
第一题:
超级水的题目,6分钟就AC了,直接上源代码
刚刚看了好多人似乎想复杂了,或者说对stoi函数不了解或者对string操作不熟练?emm,真心建议去仔细了解一下string容器,这个真是解题利器!!!
请熟悉掌握以下成员函数,好用到爆炸!!
string s1="ABC DEF"
int p1=s1.find('A')-s1.begin();//p1=0;
int p2=s1.find("DEF")-s1.begin();//p2=4(D的位置);
写完这个以后我突然发现自己有好多好多小技巧需要说,恐怕一时半会说不完,准备重开一贴,稍后把传送门贴过来。
传送门来啦,还在施工,目前提供了vector和map
#include
#include
#include
#include
using namespace std;
bool isprime(int x) {
if (x <= 1)return false;
for (int i = 2; i <= sqrt(x); i++) {
if (x%i == 0)return false;
}
return true;
}
int main() {
int num = 0;
string s;
cin >> s;
while (s.length()) {
printf("%s ", s.c_str());
if (isprime(stoi(s)))printf("Yes\n");
else {
printf("No\n");
num++;
}
s.erase(s.begin());
}
if (num == 0)printf("All Prime!\n");
return 0;
}
就是string处理数字,并且判断素数的问题,写对了isprime函数,秒过,没有任何困难。
(提示:请熟悉记住gcd求最大公因数和isprime判断素数函数)
int gcd(int x,int y){
return y==0?a:gcd(y,x%y);
}
bool isprime(int x){
if(x<=1)return false;
for(int i=2;i<=sqrt(x);i++){//必须取到等号,否则算法错误!
if(x%i==0)return fasle;
}
return true;
}
这两个函数极其有用!不服去吧PAT甲级题目刷一遍(狗头。
第二题:
代码都是考试的原生态代码,没有任何修饰,emm,可能有些生硬。
#include
#include
#include
bool possible[1000000];//表示所给的元素是否能已经有的元素差值表示
bool val[1000000];//表示已经存在某个值
bool flag[11];//标识玩家,如果是true则已经被淘汰了!
using namespace std;
vector<vector<int> >V;//相当于二维数组vector表示
int main() {
int N, M, v1, v2, v;
scanf("%d%d%d%d", &v1, &v2,&N,&M);
possible[abs(v1 - v2)] = true;//差值为true,代表可以容纳v1-v2
val[v1] = true;//v1和v2已经存在了
val[v2] = true;
V.resize(N + 1);
for (int i = 1; i <= N; i++) {
V[i].resize(M + 1);
for (int j = 1; j <= M; j++) {
scanf("%d", &V[i][j]);
}
}
vector<int>ex;//表示当前已经给出的所有合法数字
ex.push_back(v1);//v1合法
ex.push_back(v2);//v2合法
for (int i = 1; i <= M; i++) {
for (int j = 1; j <= N; j++) {
if (flag[j] == true)continue;//如果是true表示已经被淘汰了
int round = i, player = j, num = V[j][i];
if (val[num] || !possible[num]) {//不能容纳或者已经存在
flag[player] = true;//则淘汰该玩家
printf("Round #%d: %d is out.\n", round, player);
}
else {
val[num] = true;
for (int i = 0; i < ex.size(); i++) {
possible[abs(num - ex[i])] = true;//更新加入以后所有可能的值
}
ex.push_back(num);//放入合法序列
}
}
}
vector<int>tmp;
for (int i = 1; i <= N; i++) {
if (!flag[i])tmp.push_back(i);//没有被淘汰的玩家入队
}
if (tmp.size() > 0) {
printf("Winner(s):");
for (int i = 0; i < tmp.size(); i++)printf(" %d", tmp[i]);
}
else printf("No winner.");
printf("\n");
return 0;
}
第三题:
相当于验证,保存所有图之间的边以后,只需要验证一下就可,基本上做过几道图题目的人都会觉得这是送分题。
#include
#include
#include
using namespace std;
const int inf = 10000000;
int G[510][510];
vector<int>V[510];
int N, M, K;
int main() {
int v1, v2, num, val;
scanf("%d%d%d", &N, &M, &K);
for (int i = 0; i < M; i++) {
scanf("%d%d", &v1, &v2);
V[v1].push_back(v2);
V[v2].push_back(v1);
G[v1][v2] = G[v2][v1] = 1;
}
scanf("%d", &num);
for (int i = 0; i < num; i++) {
map<int, int>Ma;
vector<int>tmp;
tmp.push_back(0);
for (int j = 0; j < N; j++) {
scanf("%d", &val);
tmp.push_back(val);
Ma[val] = 1;
}
if (Ma.size() != K) {
if (Ma.size() > K)printf("Error: Too many species.\n");
else printf("Error: Too few species.\n");
}
else {
bool flag = true;
for (int i = 1; i <= N; i++) {
for (int j = 0; j < V[i].size(); j++) {
if (tmp[i] == tmp[V[i][j]]) {
flag = false;
break;
}
}
if (flag == false)break;
}
if (flag)printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
第四题:
这个题我用map排序,效率接近1了,我印象中提交代码最长处理时间是40ms,挺快的了,无需任何排序。
这个题最后一个测试点有重复数据,导致一开始我被扣了6分,然后花了我接近40分钟去排错。。
#include
#include
#include
using namespace std;
int main() {
int N, M, val;
scanf("%d%d", &N, &M);
map<int, int>Ma, Mb;
for (int i = 0; i < M; i++) {
scanf("%d", &val);
Ma[val]++;
}
vector<int>tmp;
vector<vector<int>>ans;
for (int i = M; i < N; i++) {
scanf("%d", &val);
int head = Ma.begin()->first;
if(Ma.begin()->second==1)Ma.erase(Ma.begin());
else Ma[Ma.begin()->first]--;
tmp.push_back(head);
if (val >= head)Ma[val]++;
else Mb[val]++;
if (Ma.size() == 0) {
Ma = Mb;
Mb.clear();
ans.push_back(tmp);
tmp.clear();
}
if (i == N - 1) {
while (Ma.size()) {
tmp.push_back(Ma.begin()->first);
if(Ma.begin()->second==1) Ma.erase(Ma.begin());
else Ma[Ma.begin()->first]--;
}
if (tmp.size() > 0)ans.push_back(tmp);
tmp.clear();
while (Mb.size()) {
tmp.push_back(Mb.begin()->first);
if (Mb.begin()->second == 1) Mb.erase(Mb.begin());
else Mb[Mb.begin()->first]--;
}
ans.push_back(tmp);
}
}
for (int i = 0; i < ans.size(); i++) {
for (int j = 0; j < ans[i].size(); j++) {
if (j == 0)printf("%d", ans[i][j]);
else printf(" %d", ans[i][j]);
if (j == ans[i].size() - 1)printf("\n");
}
}
return 0;
}