PAT甲级_2023春

总结

第一次模考,91分(20 16 25 30),时光机显示排名16名有点拉了。

第一题:简单打卡题,素数筛。

素数筛现场短路忘了,不过 1 0 5 10^5 105这个数量级小,就直接用埃氏筛法了

第二题:中等,用deque顺序扫描16分,TLE:

  • 涉及到排序题尽量用set、map、priority_queue,底层是红黑树,查找更快。后来改用set优化了下,但是没法提交了,有能提交的朋友可以用我代码验证下。
  • set删除第一个元素的方法巧,简单记一下。

第三题:简单打卡题。

第四题:中等,分两步:

  • 根据题意,需要得到两个内容:
    • 1、输出是否是心形。
    • 2、输出树的轮廓。
  • 先输出树的轮廓。根据题意画三笔,三笔之和得到ans数组输出:
    • 第一笔:根向左遍历到最下面
    • 第二笔:先序遍历树得到从左到右的叶子结点序列
    • 第三笔:根向右遍历到最下面,然后逆序(从下面勾上来到根)。
  • 再判断是否是心形。这个常考,就是题目给一个长相奇葩的数据结构的定义,然后给一堆数据让你构造树、图,再判断这个构造出来的满不满足奇葩数据结构的定义。方法一般是根据定义,寻找数据结构的数学特征,然后证明数学特征的充要性,再据此判断给出数据构造的图是否满足这些数学特征以判断是这种数据结构
    • 1、中序遍历序列各节点对应高度组成的新数组是对称的。因为左中右,左与右对称。
    • 2、画树的轮廓得到的叶子结点序列(第二笔)各节点对应高度组成的新数组是先非降序再非升序再非降序再非升序(根据题意),又这个数组也是对称的,所以判断数组的一半是先非降序后非升序即可。
    • 本来到了该证明充要的时候,但我一般偷懒,想到什么特征就用什么特征,毕竟证明往往比应用耗时长很多,这次幸运实现以上两个判断条件就AC了,确实不够严谨。
//素数筛
    for(int i = 2; i <= n; i ++){
        if(st2[i]) pri[cnt++] = i;
        for(int j = 0; pri[j] <= n / i ; j++){
            st2[pri[j] * i] = false;
            if(i % pri[j] == 0) break; 
        }
    }
//删除set第一个元素
    for(auto j : hist){
        hist.erase(j);
        recn[j.key] = 0, rect[j.key] = 0;
        break;
    }

A-1 The Winner over Squares and Primes

This is about a game of fighting all the squrare numbers and prime numbers.

At the very beginning, N people are sitting in N seats, and the seats are numbered from 1 to N, from left to right. Then for all the seats with their numbers being squares (such as 1, 4, 9, 16, …), those people sitting in must leave, and everyone else must shift toward left so that there is no empty seat between any of them. If there are more than one people left, the game continues, but instead of square numbers, this round will let everyone sitting in the prime seats leave, and then the rest of them will shift to fill the empty seats again.

The game continues with checking the square seats and prime seats alternatively, until there is only one winner left. You are supposed to tell the initial seat number for this winner.

Input Specification:

Each input file contains one test case, in which a positive integer N (≤105) is given.

Output Specification:

For each test case, print in a line the initial seat number for this winner.

Sample Input:

10

Sample Output:

6

Hint:

Round 1: People sitting in square seats 1, 4, and 9 will leave. The initial seat numbers for the rest of them sitting from 1 to 7 are 2, 3, 5, 6, 7, 8, 10.

Round 2: People sitting in prime seats 2, 3, 5, and 7 will leave. The initial seat numbers for the rest of them sitting from 1 to 3 are 2, 6, 8.

Round 3: People sitting in square seat 1 will leave. The initial seat numbers for the rest of them sitting from 1 to 2 are 6, 8.

Round 4: People sitting in prime seat 2 will leave. The initial seat numbers for the final winner is 6.

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
bool st1[N], st2[N];
int reco[N], cnt, pri[N], flag;
int main(){
    int n; cin>>n;
    memset(st2, true, sizeof st2);
    st1[1] = true, st2[1] = false;
    for(int i = 2; i <= n; i ++){
        reco[i] = i;
        st1[i*i] = true;
        //【1】素数筛,这里考试没想出来,用的埃氏筛法做的,因为10^5所以也不会TLE 
        if(st2[i]) pri[cnt++] = i;
        for(int j = 0; pri[j] <= n / i ; j++){
            st2[pri[j] * i] = false;
            if(i % pri[j] == 0) break; 
        }
    }
    while(n != 1){
        cnt = 1, flag = (flag + 1) % 2;
        if(flag == 1){
            for(int i = 1; i <= n; i ++){
                if(st1[i]) continue; 
                reco[cnt++] = reco[i];
            }
        }
        else if(flag == 0){
            for(int i = 1; i <= n; i ++){
                if(st2[i]) continue;
                reco[cnt++] = reco[i];
            }
        }
        n = cnt - 1;
    }
    cout<<reco[1];
    return 0;
}

A-2 LRU-K

Least Recently Used (LRU) cache scheme is to remove the least recently used frame (the one hasn’t been used for the longest amount of time) when the cache is full and a new page is referenced which is not there in cache.

LRU-K is a variant of the LRU algorithm, where K represents the number of recent uses. LRU can be considered as LRU-1. Unlike LRU, the LRU-K requires the maintenance of two different queues (for historical access and cache). The data in the historical access queue is not moved to the cache queue until the data is hit K times.

For example, assuming that the length of both queues is 5, and the memory is initialized to be empty. LRU-2 is used to process the data sequence in order: 9,5,6,7,8,3,8,9,5,9,8,3,4,7,5,6. The changes of the historical access queue and the cache queue are shown in the following table:

Your job is to implement this LRU-K cache scheme.

Input Specification:

Each input file contains one test case. For each case, the first line gives 3 positive integers: K (≤5), N (≤104) and M (≤105) which are the number of hits for cache, the size of the queues (assuming both queues have the same size) and the number of referenced page ID’s. Then M referenced page ID’s are given in the next line. A page ID is a number in the range [1,2×104]. All the numbers in a line are separated by a space.

Output Specification:

For each test case, output in the first line the page ID’s in the historical access queue, and in the second line, those in the cache queue. The ID’s are ordered from front to rear of each queue. All the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line. In case that a queue is empty, output - in a line instead.

Sample Input 1:

2 5 17
9 5 6 7 8 3 8 9 5 9 8 3 4 7 5 6 9

Sample Output 1:

4 9
8 3 7 5 6

Sample Input 2:

3 5 10
9 5 6 7 8 3 8 9 5 9

Sample Output 2:

7 3 8 5 9
-
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct no{
    int key, t;
    bool operator<(const no &A)const{
        return t < A.t;
    }
};
set<no> cache, hist;
int rect[N], recn[N];
vector<int> ans;
int main(){
    int k, n, m, a; cin>>k>>n>>m;
    for(int i = 1; i <= m; i ++){
        scanf("%d", &a);
        if(cache.find({a, rect[a]}) != cache.end()){
            cache.erase({a, rect[a]});
            cache.insert({a, i});
            rect[a] = i;
        }
        else{
            if(hist.find({a, rect[a]}) == hist.end()){
                recn[a] = 1;
                rect[a] = i;
                hist.insert({a, i});
                if(hist.size() > n){
                    for(auto j : hist){
                        hist.erase(j);
                        recn[j.key] = 0, rect[j.key] = 0;
                        break;
                    }
                }
            }
            else{
                hist.erase({a, rect[a]});
                hist.insert({a, i});
                recn[a] ++, rect[a] = i;
                if(recn[a] == k){
                    cache.insert({a, rect[a]});
                    if(cache.size() > n){
                        for(auto j : cache){
                            cache.erase(j);
                            recn[j.key] = 0, rect[j.key] = 0;
                            break;
                        }
                    }
                    hist.erase({a, i});
                }
            }
        }
    }
    if(hist.size() == 0) printf("-\n");
    else{
        for(auto i : hist) ans.push_back(i.key);
        for(int i = 0; i < ans.size() - 1; i++) printf("%d ", ans[i]);
        printf("%d\n", ans.back());
    }
    if(cache.size() == 0) printf("-");
    else{
        for(auto i : cache) ans.push_back(i.key);
        for(int i = 0; i < ans.size() - 1; i++) printf("%d ", ans[i]);
        printf("%d", ans.back());
    }
    return 0;
}

A-3 K Vertex

Given a directed graph, a K-vertex is a vertex of which the out degree is larger than the indegree. For example, the vertices a and b in the figure are K-vertices.

kv.jpg

Your job is to list all the K-vertices in a given graph.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers: N (≤200) and M, which are the number of vertices and the number of edges, respectively. Then M lines follow, each gives a directed edge <v1, v2> in the format:

v1 v2

Here we assume that all the vertices are numbered from 0 to N−1. It is guaranteed that v1 is never the same as v2.

Finally a line of N strings is given, where the i-th string corresponds to the key of the i-th vertex (i=0,⋯,N−1). Each string consists of no more than 2 lower-cased English letters.

Output Specification:

Output the keys of all the K-vertices, each occupies a line, in alphabetical order. It is guaranteed that there is at least one output.

Sample Input:

4 5
0 1
2 1
3 1
2 0
3 2
c d b a

Sample Output:

a
b
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
int cnto[N], cnti[N], n, m, v1, v2;
string nod;
vector<string> ans;
int main(){
    cin>>n>>m;
    while(m--){
        scanf("%d %d", &v1, &v2);
        cnto[v1] ++, cnti[v2] ++;
    }
    for(int i = 0; i < n; i++){
        cin>>nod;
        if(cnto[i] > cnti[i]) ans.push_back(nod);
    }
    sort(ans.begin(), ans.end());
    for(int i = 0; i< ans.size(); i ++){
        cout<<ans[i];
        if(i != ans.size() - 1) puts("");
    }
    return 0;
}

A-4 Tree of Love

heart.png

If a binary tree has its left and right subtrees perfectly symmetric. And more, if from left to right, the depths of leaves are first in increasing (or non-decreasing) then decreasing (or non-increasing), then again increasing (or non-decreasing), and finally decreasing (or non-increasing) order, then the shape of this tree looks like a heart (as shown by the above figure), and hence is called “Tree of Love”.

Given the inorder and postorder traversal sequences of a binary tree, your job is to construct this tree and test if it is a tree of love, and output its outer contour(外轮廓). “Outer contour” consists of nodes visited from the root, along the left most path to a leaf, then all the leaves from left to right, and finally back to the root along the right most path.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<100), which is the number of nodes in the tree. Then the next two lines each contains N positive keys as the inorder and postorder traversal sequences, respectively. All the keys are distinct integers no more than 103. The numbers in a line are separated by spaces. It is guaranteed that a unique binary tree can be constructed from the input.

Output Specification:

For each test case, if the tree is a tree of love, output Yes in the first line, or No if not. Then output the outer contour in the second line.

All the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line.

Sample Input 1:

27
5 4 6 22 3 23 7 20 2 21 8 18 9 1 10 19 11 24 17 25 12 26 16 27 13 15 14
5 6 22 4 7 23 20 3 8 21 9 18 2 10 11 24 19 12 26 25 13 27 14 15 16 17 1

Sample Output 1:

Yes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Sample Input 2:

11
4 8 10 2 5 1 6 3 9 11 7
10 8 4 5 2 6 11 9 7 3 1

Sample Output 2:

No
1 2 4 10 5 6 11 7 3

Hint for Sample 2:

The answer is No because the tree is not symmetric. It would be Yes if we swap 9 and 11 in the inorder sequence.

#include<bits/stdc++.h>
using namespace std;
const int N = 100;
struct node{
    int key;
    struct node* l, *r;
};
int in[N], post[N];
int sw = 0;
deque<int> ans, ans2;
vector<int> leaf, hei;
node* maketree(int il, int ir, int pl, int pr){
    if(il > ir) return NULL;
    node* a = (node*)malloc(sizeof(node));
    a->key = post[pr];
    int i = 0;
    while(in[il + i] != post[pr])i++;
    a->l = maketree(il, il + i - 1, pl, pl + i - 1);
    a->r = maketree(il + i + 1, ir, pl + i, pr - 1);
    return a;
}
void traver(node* t, int h){
    if(!t)return;
    if(sw == 0) ans.push_back(t->key);
    if(sw == 0 && !t->l){
        sw = 1;
        if(!t->r) ans.pop_back();
    }
    if(sw == 1 && !t->l && !t->r){
        ans.push_back(t->key);
        leaf.push_back(h);
    }
    traver(t->l, h + 1);
    hei.push_back(h);
    traver(t->r, h + 1);
}
void trav2(node * t){
    if(!t)return;
    ans2.push_back(t->key);
    trav2(t->r);
}
int main(){
    int n; cin>>n;
    for(int i = 0; i < n; i ++) cin>>in[i];
    for(int i = 0; i < n; i ++) cin>>post[i];
    node * t = maketree(0, n - 1, 0, n - 1);
    traver(t, 0);
    trav2(t->r);
    //删除重复元素 
    if(ans2.size() && ans.size() && ans2.back() == ans.back()) ans2.pop_back();
    //合并 
    for(int i = ans2.size() - 1; i >= 0; i--) ans.push_back(ans2[i]);
    int cnt = 0;
    bool flag = true;
    for(int i = 1; i < leaf.size() / 2; i ++){
        if(cnt == 0 && leaf[i] < leaf[i - 1]) cnt = 1;
        if(cnt == 1 && leaf[i] > leaf[i - 1]) flag = false;
    }
    for(int i = 0; i < hei.size() / 2; i ++)
        if(hei[i] != hei[hei.size() - i - 1]) flag = false;
    puts(flag ? "Yes" : "No"); 
    for(int i = 0; i < ans.size(); i++){
        printf("%d", ans[i]);
        if(i != ans.size() - 1)cout<<' ';
    }
    return 0;
}
/*
             1
        2          3
    4     5     6     7
      8             9
       10             11
4-5, 6-7
*/
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值