PAT甲级 2019年春季考试(最简短的代码)

真题估计还得一年才能补充到PAT题库里,做题还需要去教育超市购买,坑呀!这是导出分析

7-1 Sexy Primes (20分)

Sexy primes are pairs of primes of the form (p, p+6), so-named since “sex” is the Latin word for “six”. (Quoted from http://mathworld.wolfram.com/SexyPrimes.html)

Now given an integer, you are supposed to tell if it is a sexy prime.

Input Specification:

Each input file contains one test case. Each case gives a positive integer N (≤108).

Output Specification:

For each case, print in a line Yes if N is a sexy prime, then print in the next line the other sexy prime paired with N (if the answer is not unique, output the smaller number). Or if N is not a sexy prime, print No instead, then print in the next line the smallest sexy prime which is larger than N.

Sample Input 1:

47

Sample Output 1:

Yes
41

Sample Input 2:

21

Sample Output 2:

No
23
  • 题意:性感素数是一种素数对,形如 (p, p + 6),其中 p 和 p+6 都是素数,即其差值为6。题目要求,如果n是性感素数,则输出与n配对的另一个素数,如果答案不唯一则输出较小的那个,比如n-6与n+6都是素数,则输出n-6;如果n不是性感素数,则输出大于n的最小性感素数。
  • 分析:根据题目要求,直接同时判定 n和n-6 或 n和n+6 是不是均为素数,如果两个情况都不满足,说明n不是性感素数,则n一直++,当n为素数时候,判断 n-6 或者 n+6 是不是素数即可。
#include <cstdio>
bool isprime(int x) {
    if (x <= 1) return false;
    for (int i = 2; i * i <= x; i++)
        if (x % i == 0) return false;
    return true;
}
int main() {
    int n;
    scanf("%d", &n);
    if (isprime(n) && isprime(n - 6)) printf("Yes\n%d", n - 6);
    else if (isprime(n) && isprime(n + 6)) printf("Yes\n%d", n + 6);
    else {
        while (true) {
            n++;
            if (isprime(n) && (isprime(n - 6) || isprime(n + 6))) break;
        }
        printf("No\n%d", n);
    }
    return 0;
}

7-2 Anniversary (25分)

Zhejiang University is about to celebrate her 122th anniversary in 2019. To prepare for the celebration, the alumni association (校友会) has gathered the ID’s of all her alumni. Now your job is to write a program to count the number of alumni among all the people who come to the celebration.

Input Specification:

Each input file contains one test case. For each case, the first part is about the information of all the alumni. Given in the first line is a positive integer N (≤105). Then N lines follow, each contains an ID number of an alumnus. An ID number is a string of 18 digits or the letter X. It is guaranteed that all the ID’s are distinct.

The next part gives the information of all the people who come to the celebration. Again given in the first line is a positive integer M (≤105). Then M lines follow, each contains an ID number of a guest. It is guaranteed that all the ID’s are distinct.

Output Specification:

First print in a line the number of alumni among all the people who come to the celebration. Then in the second line, print the ID of the oldest alumnus – notice that the 7th - 14th digits of the ID gives one’s birth date. If no alumnus comes, output the ID of the oldest guest instead. It is guaranteed that such an alumnus or guest is unique.

Sample Input:

5
372928196906118710
610481197806202213
440684198612150417
13072819571002001X
150702193604190912
6
530125197901260019
150702193604190912
220221196701020034
610481197806202213
440684198612150417
370205198709275042

Sample Output:

3
150702193604190912
  • 题意:浙大准备在2019年举办122周年庆,题目先给出一份浙大校友名单,再给出一份要来参加浙大周年庆的宾客名单,需要记录宾客中有多少个浙大校友,如果宾客中有校友则输出年龄最大的那位校友的ID,如果宾客名单中不存在校友,则输出宾客中年龄最大的宾客的ID。
  • 分析:首先用map记录校友的ID,设置两个字符串类型的变量oldestAlumni = "xxxxxx99999999", oldestGuest = "xxxxxx99999999"分别存年纪最大的校友和宾客的ID,年纪最大实际上就是生日最小,所以生日的初始值设置为最大99999999,输入宾客名单同时总是记录宾客中最老的那个,如果是校友再另行判断。最后直接根据计数的cnt判断输出哪个ID。这思路简直不要太简单了,哈哈。
#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, m, cnt = 0;
    string oldestAlumni = "xxxxxx99999999", oldestGuest = "xxxxxx99999999", id;
    scanf("%d", &n);
    map<string, bool> isalumni;
    for (int i = 0; i < n; i++) {
        cin >> id;
        isalumni[id] = true;
    }
    scanf("%d", &m);
    for (int i = 0; i < m; i++) {
        cin >> id;
        if (id.substr(6, 8) < oldestGuest.substr(6, 8)) oldestGuest = id;
        if (isalumni[id]) {
            if (id.substr(6, 8) < oldestAlumni.substr(6, 8)) oldestAlumni = id;
            cnt++;
        }
    }
    printf("%d\n%s", cnt, cnt > 0 ? oldestAlumni.c_str() : oldestGuest.c_str());
    return 0;
}

7-3 Telefraud Detection (25分)

Telefraud(电信诈骗) remains a common and persistent problem in our society. In some cases, unsuspecting victims lose their entire life savings. To stop this crime, you are supposed to write a program to detect those suspects from a huge amount of phone call records.

A person must be detected as a suspect if he/she makes more than K short phone calls to different people everyday, but no more than 20% of these people would call back. And more, if two suspects are calling each other, we say they might belong to the same gang. A makes a short phone call to B means that the total duration of the calls from A to B is no more than 5 minutes.

Input Specification:

Each input file contains one test case. For each case, the first line gives 3 positive integers K (≤500, the threshold(阈值) of the amount of short phone calls), N (≤103, the number of different phone numbers), and M (≤105, the number of phone call records). Then M lines of one day’s records are given, each in the format:

caller receiver duration

where caller and receiver are numbered from 1 to N, and duration is no more than 1440 minutes in a day.

Output Specification:

Print in each line all the detected suspects in a gang, in ascending order of their numbers. The gangs are printed in ascending order of their first members. The numbers in a line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.

If no one is detected, output None instead.

Sample Input 1:

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

Sample Output 1:

3 5
6

Note: In sample 1, although 1 had 9 records, but there were 7 distinct receivers, among which 5 and 15 both had conversations lasted more than 5 minutes in total. Hence 1 had made 5 short phone calls and didn’t exceed the threshold 5, and therefore is not a suspect.

Sample Input 2:

5 7 8
1 2 1
1 3 1
1 4 1
1 5 1
1 6 1
1 7 1
2 1 1
3 1 1

Sample Output 2:

None
  • 题意:电信诈骗问题,很多人每天都会收到诈骗电话,题目要求通过给出的通话记录找到可能的诈骗犯和诈骗团伙,通话记录中,如果有人一天内打了k个短途电话(通话时长小于等于5分钟),且这些拨过去的短途电话里,只有不到20%的人回了电话,那这个拨号者就会被认为是诈骗嫌疑人,如果两个人诈骗嫌疑人彼此拨打过电话则视他们是一个团伙。题目给出阈值k(即拨打的短途电话数量)、不同的电话号码的数量n(编号从1到n)、m条通话记录。注意:一个人可能一天给同一个人拔打了多次电话,只有和对方的通话总时长小于等于5才被视作为一个短途电话。

  • 这是四道题里比较麻烦的啦,把思路缕清,解题步骤还是比较清晰的。

    1. 第一步:设置record数组存储通话时长,如record[a][b]表示a给b拨打的电话时长,题目给的电话号码(也可看作人物编号)从1到n依次编号,所以遍历1到n,如果这个人总的通话次数都不超过k,那肯定不会是嫌疑人,之后遍历record[i],如果拨号者和某人的通话时长小于等于5分钟,那就callto++,同时判断对方是否拨回过电话,有拨回则callback++,最后如果callto大于k且callback和callto的比值小于等于0.2,则添加到嫌疑人名单。
    2. 第二步:找出嫌疑人名单之后就是找到团伙,要用到并查集,两两比较两个嫌疑人之间是否彼此拨过电话,将符合条件的嫌疑人合并到一个集合,之后就是分别输出各个集合了。这里值得注意的是,题目输出要求每个团伙占一行,每行按团伙中人员的编号升序输出,团伙之间则是按照团伙第一个人的编号升序排序。所以并查集的合并方法需要修改成总将较小的作为father,这样最后集合的根一定是里面数值最小的,再之后,团伙间也要有序,则是通过有序map自动排序,同时输出一个团伙时要对团伙中所有人重新排序。如果没有诈骗嫌疑人则输出 None。
    #include <bits/stdc++.h>
    using namespace std;
    int father[1010];
    int findFather(int x) {
        return x == father[x] ? x : father[x] = findFather(father[x]);
    }
    void uni(int a, int b) {
        int faA = findFather(a);
        int faB = findFather(b);
        if (faA < faB) father[faB] = faA;
        if (faA > faB) father[faA] = faB;
    }
    int main() {
        for (int i = 0; i < 1010; i++) father[i] = i;
        int k, n, m, a, b, time;
        scanf("%d%d%d", &k, &n, &m);
        vector<map<int, int> > record(n + 1);
        for (int i = 0; i < m; i++) {
            scanf("%d%d%d", &a, &b, &time);
            record[a][b] += time;
        }
        vector<int> suspect;
        for (int i = 1; i <= n; i++) {
            if (record[i].size() <= k) continue;
            int callto = 0, callback = 0;
            for (auto it : record[i]) {
                if (it.second <= 5) {
                    callto++;
                    if (record[it.first].find(i) != record[it.first].end()) callback++;
                }
            }
            if (callto > k && callback * 1.0 / callto <= 0.2) suspect.push_back(i);
        }
        if (suspect.size() == 0) {
            printf("None\n");
            return 0;
        }
        for (int i = 0; i < suspect.size() - 1; i++) {
            for (int j = i + 1; j < suspect.size(); j++) {
                a = suspect[i]; b = suspect[j];
                if (record[a][b] > 0 && record[b][a] > 0) uni(a, b);
            }
        }
        map<int, vector<int> > mp;
        for (auto it : suspect) mp[findFather(it)].push_back(it);
        for (auto it : mp) {
            vector<int> gang = move(it.second);
            sort(gang.begin(), gang.end());
            for (int i = 0; i < gang.size(); i++) {
                if (i != 0) printf(" ");
                printf("%d", gang[i]);
            }
            printf("\n");
        }
        return 0;
    }
    

7-4 Structure of a Binary Tree (30分)

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, a binary tree can be uniquely determined.

Now given a sequence of statements about the structure of the resulting tree, you are supposed to tell if they are correct or not. A statment is one of the following:

  • A is the root
  • A and B are siblings
  • A is the parent of B
  • A is the left child of B
  • A is the right child of B
  • A and B are on the same level
  • It is a full tree

Note:

  • Two nodes are on the same level, means that they have the same depth.
  • A full binary tree is a tree in which every node other than the leaves has two children.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are no more than 103 and are separated by a space.

Then another positive integer M (≤30) is given, followed by M lines of statements. It is guaranteed that both A and B in the statements are in the tree.

Output Specification:

For each statement, print in a line Yes if it is correct, or No if not.

Sample Input:

9
16 7 11 32 28 2 23 8 15
16 23 7 32 11 2 28 15 8
7
15 is the root
8 and 2 are siblings
32 is the parent of 11
23 is the left child of 16
28 is the right child of 2
7 and 11 are on the same level
It is a full tree

Sample Output:

Yes
No
Yes
No
Yes
Yes
Yes
  • 题意:给出一个二叉树的后序和中序遍历序列,题目读入m条命题,判断给出的命题是否正确。(具体见上面的说明样例)
  • 分析:这是一道纯考数据结构的题啦,这道题我思考过两种做法,做法一:通过顺序存储的方式存储二叉树,优点是直接通过结点的编号就能判断结点间的关系。首先对中后序遍历序列复原二叉树的函数做一点调整,函数参数加上 idepth 用于传递结点编号和深度,稍微麻烦一点的就是是否为满树需要单独判断,循环遍历所有的结点,如果存在一个非叶子结点只有一个孩子那这就不是满树,同时,因为题目说每个结点是不同的正整数,所以直接使用数组做哈希表记录下每个结点的序号。输入命题部分,只需要通过string取子串的方式就好了,用stoi函数将字符串转为整型,之后就是通过结点序号关系判断命题是否正确。做法二:和上面没有太大差异,只需要多设置几个相关的数组去记录父子结点关系、层数等即可。

另外要注意的是,最开始用 i * 2 大于 len(最大的结点编号)来判断为叶子结点是不对的,我只是用顺序存储方式存储二叉树,但它并不是一颗完全二叉树,这里应该用 tree[i * 2] 的数值是不是为0(或表示为-1也行)来判断是不是叶子结点。最后,题目说 A full binary tree is a tree in which every node other than the leaves has two children. 这明明就不是真正的满二叉树呀,可能是陈越姥姥为了降低题目难度才这样定义吧。

解法一:

#include <bits/stdc++.h>
using namespace std;
vector<int> post, in;
int tree[1010], pos[1010], level[1010];
int len = -1;
int create(int postl, int postr, int inl, int inr, int i, int depth) {
    if (postl > postr) return 0;
    len = max(len, i);
    level[post[postr]] = depth;
    tree[i] = post[postr];
    int k = inl;
    while (k <= inr && in[k] != post[postr]) k++;
    int numLeft = k - inl;
    tree[i * 2] = create(postl, postl + numLeft - 1, inl, k - 1, i * 2, depth + 1);
    tree[i * 2 + 1] = create(postl + numLeft, postr - 1, k + 1, inr, i * 2 + 1, depth + 1);
    return post[postr];
}
int main() {
    int n, m;
    scanf("%d", &n);
    post.resize(n);
    in.resize(n);
    for (int i = 0; i < n; i++) scanf("%d", &post[i]);
    for (int i = 0; i < n; i++) scanf("%d", &in[i]);
    create(0, n - 1, 0, n - 1, 1, 1);
    bool isfull = true;
    for (int i = 1; i <= len; i++) {
        if (tree[i] == 0) continue;
        pos[tree[i]] = i;
        if ((tree[i * 2] != 0 || tree[i * 2 + 1] != 0) &&
            (tree[i * 2] * tree[i * 2 + 1] == 0)) {
            isfull = false;
        }
    }
    scanf("%d", &m);
    getchar();
    while (m--) {
        string s;
        bool ans;
        getline(cin, s);
        if (s[0] == 'I') ans = isfull;
        else {
            int a = stoi(s.substr(0, s.find_first_of(' ')));
            if (s[s.length() - 1] == 't') ans = pos[a] == 1;
            else if (isdigit(s[s.length() - 1])) {
                int b = stoi(s.substr(s.find_last_of(' ') + 1));
                if (s.find("pa") != string::npos) ans = pos[a] == pos[b] / 2;
                else if (s.find("le") != string::npos) ans = pos[a] == pos[b] * 2;
                else ans = pos[a] == pos[b] * 2 + 1;
            } else {
                s.erase(0, s.find_first_of(' '));
                while (!isdigit(s[0])) s.erase(s.begin());
                int b = stoi(s.substr(0, s.find_first_of(' ')));
                if (s[s.length() - 1] == 's') ans = pos[a] / 2 == pos[b] / 2;
                else ans = level[a] == level[b];
            }
        }
        printf("%s\n", ans ? "Yes" : "No");
    }
    return 0;
}

解法二:

#include <bits/stdc++.h>
using namespace std;
int post[35], in[35], numlevel = 1;
bool isfull = true;
map<int, int> father, lchild, rchild, level;
string s;
int create(int postl, int postr, int inl, int inr, int depth) {
    if (postl > postr) return 0;
    int root = post[postr];
    int k = inl;
    while (in[k] != post[postr]) k++;
    int numleft = k - inl;
    int left = create(postl, postl + numleft - 1, inl, k - 1, depth + 1);
    int right = create(postl + numleft, postr - 1, k + 1, inr, depth + 1);
    if ((left == 0 && right != 0) || (left != 0 && right == 0)) isfull = false;
    father[left] = father[right] = root;
    lchild[root] = left;
    rchild[root] = right;
    level[left] = level[right] = depth++;
    return root;
}
bool find(string val) { return s.find(val) != string::npos; }
int main() {
    int n, m;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &post[i]);
    for (int i = 0; i < n; i++) scanf("%d", &in[i]);
    scanf("%d", &m);
    getchar();
    int root = create(0, n - 1, 0, n - 1, 1);
    while (m--) {
        getline(cin, s);
        bool ans;
        if (!isdigit(s[0])) {
            ans = isfull;
        } else {
            int a, i = 0;
            while (isdigit(s[i])) i++;
            a = stoi(s.substr(0, i));
            if (s[s.length() - 1] == 't') {
                ans = (root == a);
            } else if (s.find("of") != string::npos) {
                int start = s.length() - 1;
                while (isdigit(s[start])) start--;
                int b = stoi(s.substr(++start));
                if (find("pa")) ans = (father[b] == a);
                else if (find("le")) ans = (lchild[b] == a);
                else if (find("ri")) ans = (rchild[b] == a);
            } else {
                while (!isdigit(s[i])) i++;
                int left = i;
                while (isdigit(s[i])) i++;
                int b = stoi(s.substr(left, i - left + 1));
                if (find("sib")) ans = (father[a] == father[b]);
                else ans = (level[a] == level[b]);
            }
        }
        printf("%s\n", ans ? "Yes" : "No");
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值