刚Co老师打游戏,他说:“不试试,真的不知道自己其实还是挺厉害的。”
确实,不试试,真的不知道也许以后还是有机会的吧。
前情 大概就是为了检验跟Co老师学习了几天的学习成果,和Co老师一起去传媒考了PAT。Co老师是 Top Level
,我是 Advanced Level
。Co老师满分了,但我只有63分。(虽然好像Co老师甲级也拿不到满分,因为第一题太坑了)但Co老师给我的两个目标还真就勉勉强强达到了:
做出两道题
及格
题目 Arrays and Linked Lists 20分的题目,我只拿了13分。后来发现读错了题意……这题有一个坑点,后面会具体提到。
题意 对于数组 ,有 个元素,起始地址为 。每次一个询问 ,询问的是数组中下标为 的元素(即 )的地址。题目会给几组数组,且分别给定每个数组的起始地址。
例如,题目给了两个数组 和 。如果 (因为数组下标从 开始,所以是小于号),则返回 ;如果 且 ,则返回 ;如果 ,则输出Illegal Access
。
对于每次询问需要输出地址。且在最后打印有多少个数组被声明。
扫盲 !!!被声明!!!!
需要注意的是,如果我们询问的区间包含了第 个数组,那么它和它前面所有的数组都是被声明过的。我考试的时候以为是询问涉及到了几个数组,最后就输出几。(这都有13分……)
还有一个坑点,就是如果每次访问都是非法的,最后输出的不是 ,而是 。
注意到这些坑点,这道题也没那么难了。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <bits/stdc++.h> #define N 1000007 using namespace std ;inline int rd () { int x = 0 ; bool f = 0 ; char c = getchar(); for (; !isdigit (c); c = getchar()) f |= (c == '-' ); for (; isdigit (c); c = getchar()) x = x * 10 + (c ^ 48 ); return f ? -x : x; } int a[N], bl[N], sum, ans = 1 ;int main () { int n = rd(); int m = rd(); for (int i = 1 ; i <= n; ++i) { int ad = rd(); int len = rd(); for (int j = 0 ; j < len; ++j, ++sum) { a[sum] = ad + j * 4 ; bl[sum] = i; } } for (int i = 1 ; i <= m; ++i) { int x = rd(); if (x >= sum) {puts ("Illegal Access" ); continue ;} printf ("%d\n" , a[x]); ans = max(ans, bl[x]); } printf ("%d\n" , ans); return 0 ; }
Stack of Hats 题意 一摞帽子,帽子各有大小,从下到上给出各帽子的大小。一群人,编号从 到 ,每一个人需要按体重分配一顶帽子。
输出帽子从上到下所配对的人的编号。
思路 我也不知道这题在考什么……瞎做。就排序,疯狂排序。
开两个结构体数组,一个是帽子的,一个是人的。结构体里三个值,id
代表编号。帽子的编号最初代表上下关系,因为最后输出需要按帽子从上到下的顺序,把最下面的帽子编号为 ,最上面的编号为 ,后面存储了与它相对应的人的编号。number
代表排序后所在的位置。 value
对于帽子来说就是大小,对于人来说就是体重。
先把两个结构体数组都按 value
值排序,记录 number
,对于帽子数组,还需再按 id
排序过。然后将帽子与人进行匹配,将人的 id
存储到帽子数组的 id
。最后按相应的顺序进行输出。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <bits/stdc++.h> #define N 10007 using namespace std ;int n, k, num = 0 ;struct node { int number; int id; int value; }hat[N], person[N]; inline int rd () { char c = getchar(); int x = 0 ; while (!isdigit (c)) c = getchar(); while (isdigit (c)){ x = x * 10 + c - '0' ; c = getchar(); } return x; } bool cmp1 (node a, node b) { return a.value > b.value; } bool cmp2 (node a, node b) { return a.id < b.id; } int main () { n = rd(); for (int i = 1 ; i <= n; ++i){ hat[i].id = i; hat[i].value = rd(); } sort(hat + 1 , hat + n + 1 , cmp1); for (int i = 1 ; i <= n; ++i) hat[i].number = i; sort(hat + 1 , hat + n + 1 , cmp2); for (int i = 1 ; i <= n; ++i){ person[i].id = i; person[i].value = rd(); } sort(person + 1 , person + n + 1 , cmp1); for (int i = 1 ; i <= n; ++i) person[i].number = i; for (int i = n; i > 0 ; --i){ for (int j = 1 ; j <= n; ++j){ if (person[j].number == hat[i].number){ hat[i].id = person[j].id; break ; } } } printf ("%d" ,hat[n].id); for (int i = n - 1 ; i > 0 ; --i){ printf (" %d" , hat[i].id); } return 0 ; }
Playground Exploration 题意 一个无向图有 个点, 条边。每次选择与当前点相连的点中编号最小的点进行移动,且每个点只能访问一次。问从哪个点开始移动,可到达的点数最多。输出这个点和可到达的点数。
思路 本来是想用邻接表存图的,但如果用邻接表我不知道怎么排序选择编号最小的点移动。 也不大,所以就用邻接矩阵了。
因为每个点只能走一次,故用 vis
数组打标记。mxlen
存储最后的答案。枚举起点,dfs
计算路径长度。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <bits/stdc++.h> #define N 107 using namespace std ;int n, m, mxlen, ans, vis[N], mx;int a[N][N];int rd () { char c = getchar(); int x = 0 ; while (!isdigit (c)) c = getchar(); while (isdigit (c)){ x = x * 10 + c - '0' ; c = getchar(); } return x; } int dfs (int x, int len) { if (mx < len) mx = len; vis[x] = 1 ; for (int i = 1 ; i <= n; ++i){ if (!vis[i] && a[x][i] == 1 ) dfs(i, len + 1 ); } return mx; } int main () { n = rd(); m = rd(); for (int i = 1 ; i <= m; ++i){ int u = rd(), v = rd(); a[u][v] = 1 ; a[v][u] = 1 ; } for (int i = 1 ; i <= n; ++i){ for (int j = 1 ; j <= n; ++j) vis[j] = 0 ; mx = 0 ; int t = dfs(i, 1 ); if (t > mxlen){ mxlen = t; ans = i; } } printf ("%d %d" , ans, mxlen); return 0 ; }
Sorted Cartesian Tree 题意 每个结点有两个值。 key
和 priority
。要求建一棵树满足以下条件:
对于 priority
来说,这棵树是一个小顶堆。
对于 key
来说,中序遍历得到的序列是增序。
最后输出这一棵树的层次遍历,第一行是对应的 key
第二行是对应的 priority
。
思路 这就是我0分的题……
考试的时候连题目都没看懂…… 大概就是排序什么的,但没看懂是个什么顺序,考完试Co老师说这是顶级的第一题。
首先根据要求 1,对于这棵树和这棵树的每一个子树来说,priority
最小的点一定是根。再根据要求 2,我们可以根据根的值,确定剩下的点在根的左子树上还是右子树上,这就是 divide
函数的作用。
层次遍历其实就是 bfs
可以借助一个队列完成。
温馨小提示:访问 vector
里面的东西可以用 []
。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <bits/stdc++.h> #define N 37 using namespace std ;inline int rd () { int x = 0 ; bool f = 0 ; char c = getchar(); for (; !isdigit (c); c = getchar()) f |= (c == '-' ); for (; isdigit (c); c = getchar()) x = x * 10 + c - '0' ; return f ? -x : x; } struct node { int k, p; }a[N]; int ls[N], rs[N];int divide (vector <int > s) { if (s.empty()) return -1 ; int root = s[0 ]; for (auto i : s) if (a[i].p < a[root].p) root = i; vector <int > l, r; for (auto i : s) if (i == root) continue ; else a[i].k < a[root].k ? l.push_back(i): r.push_back(i); ls[root] = divide(l); rs[root] = divide(r); return root; } vector <int > id;int main () { int n = rd(); vector <int > s; for (int i = 1 ; i <= n; ++i){ a[i].k = rd(); a[i].p = rd(); s.push_back(i); } int Root = divide(s); queue <int > q; q.push(Root); while (!q.empty()){ int t = q.front(); q.pop(); if (ls[t] != -1 ) q.push(ls[t]); if (rs[t] != -1 ) q.push(rs[t]); id.push_back(t); } printf ("%d" , a[id[0 ]].k); for (int i = 1 ; i < n; ++i) printf (" %d" , a[id[i]].k); printf ("\n%d" , a[id[0 ]].p); for (int i = 1 ; i < n; ++i) printf (" %d" , a[id[i]].p); return 0 ; }
彩蛋 因为Co老师比我早出考场大概两个小时,所以有时间去拍拍浙传,而我就只配盗图了。