2021年3月春季PAT甲级考试题解

7-1 Arithmetic Progression of Primes (20 分)

In mathematics, an arithmetic progression (AP,等差数列) is a sequence of numbers such that the difference between the consecutive terms is constant. In 2004, Terence Tao (陶哲轩) and Ben Green proved that for any positive n, there exists at least one arithmetic progression consists of n consecutive prime numbers. For example, { 7,37,67,97,127,157 } is one solution for n=6. Now it is your job to find a maximum solution for a given n within a given range.

Input Specification:
Each input file contains one test case, which gives two positive integers in a line: n (≤10), the number of consecutive prime terms in an arithmetic progression, and MAXP (2≤MAXP<10 ^5
), the upper bound of the largest prime in the solution.

Output Specification:
For each test case, if there exists a solution, print in ascending order the prime numbers in a line. If the solution is not unique, output the one with the maximum common difference. If there is still a tie, print the one with the maximum first number. If there is no solution bounded by MAXP, output the largest prime in the given range instead.

All the numbers in a line must be separated by a space, and there must be no extra space at the beginning or the end of the line.
Sample Input 1:
5 1000
Sample Output 1:
23 263 503 743 983

Sample Input 2:
10 200
Sample Output 2:
199
分析
输入两个数,len和n,求1~n中,公差最大的,最靠近后面的等差质数数列
暴力即可过

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int len, n;
bool vis[N];

void shai()//质数筛,埃氏筛法
{
    vis[1] = vis[0] = 1;
    for (int i = 2; i < N;i++){
        if(!vis[i]){
            for (int j = 2 * i; j < N;j+=i)
                vis[j] = 1;
        }
    }
}
bool check(int x,int d)//判断最后一项为x,公差为d的情况,是否为等差序列
{
    for (int i = 1; i < len;i++)
        if(vis[x-i*d])
            return 0;
    return 1;
}
int main() 
{
    shai();
    cin >> len >> n;
    if(len==1)//特判等差序列长度为1的情况,直接输出最大的质数
    {
        while(vis[n])
            n--;
        cout << n;
        return 0;
    }
    int d = n / (len - 1);//枚举公差,从大到小枚举
    while(d){
        for (int i = n;;i--){
            if(i-(len-1)*d<=1)//最小的一项小于1,直接退出
                break;
            if(!vis[i]){//从质数开始枚举
                if(check(i,d)){
                    for (int j = len - 1; j >= 0;j--){
                        cout << i - j * d;
                        if(j)//中间输出空格
                            cout << " ";
                    }
                    return 0;
                }
            }
        }
        d--;
    }
    while(vis[n])//没找到答案,输出最大质数
        n--;
    cout << n;
    return 0;
}

7-2 Lab Access Scheduling (25 分)

Nowadays, we have to keep a safe social distance to stop the spread of virus due to the COVID-19 outbreak. Consequently, the access to a national lab is highly restricted. Everyone has to submit a request for lab use in advance and is only allowed to enter after the request has been approved. Now given all the personal requests for the next day, you are supposed to make a feasible plan with the maximum possible number of requests approved. It is required that at most one person can stay in the lab at any particular time.

Input Specification:
Each input file contains one test case. Each case starts with a positive integer N (≤2×10 ^3), the number of lab access requests. Then N lines follow, each gives a request in the format:
hh:mm:ss hh:mm:ss
where hh:mm:ss represents the time point in a day by hour:minute:second, with the earliest time being 00:00:00 and the latest 23:59:59. For each request, the two time points are the requested entrance and exit time, respectively. It is guaranteed that the exit time is after the entrance time.

Note that all times will be within a single day. Times are recorded using a 24-hour clock.
Output Specification:
The output is supposed to give the total number of requests approved in your plan.

Sample Input:
7
18:00:01 23:07:01
04:09:59 11:30:08
11:35:50 13:00:00
23:45:00 23:55:50
13:00:00 17:11:22
06:30:50 11:42:01
17:30:00 23:50:00

Sample Output:
5

Hint:
All the requests can be approved except the last two.

分析 给定n个区间时间,求每一天,最多有多少个区间。

区间贪心:将区间右端点排序,遍历一天统计即可。

#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int>pii;
int n;
vector<pii> ans;
int main()
{
    cin >> n;
    int h1, m1, s1, h2, m2, s2;
    while(n--){
        scanf("%d:%d:%d %d:%d:%d", &h1, &m1, &s1, &h2, &m2, &s2);
        ans.push_back(pii(h1 * 3600+ m1 * 60 + s1, h2 * 3600+ m2 * 60+ s2));
    }
    sort(ans.begin(), ans.end(), [](pii &a, pii &b)
         { return a.second < b.second; });//按右端点从小到大排序
    int st = -1, ed = -1;
    int cnt = 0;
    for(pii&p:ans){
        if(p.first>=ed){
            cnt++;
            st = p.first, ed = p.second;
        }
    }
    cout << cnt;
    return 0;
}

7-3 Structure of Max-Heap (25 分)

In computer science, a max-heap is a specialized tree-based data structure that satisfies the heap property: if P is a parent node of C, then the key (the value) of P is greater than or equal to the key of C. A common implementation of a heap is the binary heap, in which the tree is a complete binary tree.

Your job is to first insert a given sequence of integers into an initially empty max-heap, then to judge if a given description of the resulting heap structure is correct or not. There are 5 different kinds of description statements:

x is the root
x and y are siblings
x is the parent of y
x is the left child of y
x is the right child of y

Input Specification:
Each input file contains one test case. For each case, the first line gives 2 positive integers: N (≤1,000), the number of keys to be inserted, and M (≤20), the number of statements to be judged. Then the next line contains N distinct integer keys in [−10 ^4,10 ^4] which are supposed to be inserted into an initially empty max-heap. Finally there are M lines of statements, each occupies a line.

Output Specification:
For each statement, print 1 if it is true, or 0 if not. All the answers must be print in one line, without any space.

Sample Input:
5 6
23 46 26 35 88
35 is the root
46 and 26 are siblings
88 is the parent of 46
35 is the left child of 26
35 is the right child of 46
-1 is the root

Sample Output:
011010
分析 题目先描述了大顶堆的定义,即父节点的值大于等于子节点的值。
给定n个数,建成一个大顶堆,再给定m个询问,对于每个询问,输出0和1,对应错误和正确。
本题跟天梯赛中这一题关于堆的判断基本一样

#include <bits/stdc++.h>
using namespace std;

unordered_set<int> S;//哈希表,保存出现过的数
const int N = 1010;
int heap[N];
int n, m;

void upjust(int low, int high)//算法笔记中向上调整的模板函数
{
    int i = high, j = i / 2;
    while (j >= low)
    {
        if (heap[j] < heap[i])
        {
            swap(heap[i], heap[j]);
            i = j;
            j = i / 2;
        }
        else
            break;
    }
}
bool judge1(int x)//判断是否是根
{
    if (!S.count(x))
        return 0;
    return x == heap[1];
}
bool judge2(int x, int y)//x和y是否是兄弟节点
{
    if (!S.count(x) || !S.count(y))
        return 0;
    int dx, dy;
    for (int i = 1; i <= n; i++)
    {
        if (heap[i] == x)
            dx = i;
        if (heap[i] == y)
            dy = i;
    }
    return dx / 2 == dy / 2;
}
bool judge3(int x, int y)//x是否是y的父亲节点
{
    if (!S.count(x) || !S.count(y))
        return 0;
    int dx, dy;
    for (int i = 1; i <= n; i++)
    {
        if (heap[i] == x)
            dx = i;
        if (heap[i] == y)
            dy = i;
    }
    return dx == dy / 2;
}
bool judge4(int x, int y)//x是y的左儿子节点?
{
    if (!S.count(x) || !S.count(y))
        return 0;
    int dx, dy;
    for (int i = 1; i <= n; i++)
    {
        if (heap[i] == x)
            dx = i;
        if (heap[i] == y)
            dy = i;
    }
    return dx == dy * 2;
}
bool judge5(int x, int y)//x是y的右儿子节点?
{
    if (!S.count(x) || !S.count(y))
        return 0;
    int dx, dy;
    for (int i = 1; i <= n; i++)
    {
        if (heap[i] == x)
            dx = i;
        if (heap[i] == y)
            dy = i;
    }
    return dx == dy * 2 + 1;
}


int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        cin >> heap[i];
        S.insert(heap[i]);
        upjust(1, i);//向上调整
    }
    while (m--)
    {
        int x, y;
        string op;
        cin >> x >> op;

        if (op == "and"){
            cin >> y >> op >> op;
            cout << judge2(x, y);
        }
        else
        {
            cin >> op >> op;
            if (op == "root")
                cout << judge1(x);
            else if (op == "parent")
            {
                cin >> op >> y;
                cout << judge3(x, y);
            }
            else if (op == "left")
            {
                cin >> op >> op >> y;
                cout << judge4(x, y);
            }
            else{
                cin >> op >> op >> y;
                cout << judge5(x, y);
            }
        }
    }
    return 0;
}

7-4 Recycling of Shared Bicycles (30 分)

There are many spots for parking the shared bicycles in Hangzhou. When some of the bicycles are broken, the management center will receive a message for sending a truck to collect them. Now given the map of city, you are supposed to program the collecting route for the truck. The strategy is a simple greedy method: the truck will always move to the nearest spot to collect the broken bicycles. If there are more than one nearest spot, take the one with the smallest index.

Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers: N (≤ 200), the number of spots (hence the spots are numbered from 1 to N, and the management center is always numbered 0), and M, the number of streets connecting those spots. Then M lines follow, describing the streets in the format:

S1 S2 Dist
where S1 and S2 are the spots at the two ends of a street, and Dist is the distance between them, which is a positive integer no more than 1000. It is guaranteed that each street is given once and S1 is never the same as S2.

Output Specification:
For each case, first print in a line the sequence of spots in the visiting order, starting from 0. If it is impossible to collect all the broken bicycles, output in the second line those spots that cannot be visited, in ascending order of their indices. Or if the job can be done perfectly, print in the second line the total moving distance of the truck.

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 (shown by the figure below):
7 10
0 2 1
0 4 5
0 7 3
0 6 4
0 5 5
1 2 2
1 7 2
2 3 4
3 4 2
6 7 9
在这里插入图片描述
Sample Output 1:
0 2 1 7 6 3 4 5
33

Sample Input 2:
7 8
0 2 1
0 4 5
0 7 3
1 2 2
1 7 2
2 3 4
3 4 2
6 5 1

Sample Output 2:
0 2 1 7 3 4
5 6

分析
给定n个点,m条边,从0号点出发,采用贪心策略,判断是否能遍历完一个图。能遍历完,输出遍历的每一个点和距离和,否则输出不能走到的点。全局最短路算法,采用弗洛伊德算法,n最大为200,时间复杂度为n ^ 3,8*1e6,OK。注意的是弗洛伊德算法枚举中间点k的时候,必须在第一层循环,这个点坑了我好久。。。

#include <bits/stdc++.h>
using namespace std;

const int N = 210, inf = 1e8;
int dis[N][N];
bool vis[N];
int n, m, sum = 0;
vector<int> ans;
void floyd()
{
    for (int k = 0; k <= n; k++){//枚举中间点,k在最外层循环
        for (int i = 0; i <= n; i++){
            for (int j = 0; j <= n; j++){
                if (i == j)
                    dis[i][j] = 0;
                else
                    dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
}
void dfs(int u)//从u出发,到达下一个点
{
    ans.push_back(u);
    vis[u] = 1;
    int v = -1, minn = inf;
    for (int j = 1; j <= n; j++)
    {
        if (!vis[j] && dis[u][j] < minn){//找到一个没有走过的点,且距离最短的点
            v = j;
            minn = dis[u][j];
        }
    }
    if(v==-1)//找不到可以走的点,退出
        return;
    sum += minn;
    dfs(v);
}

void output(vector<int> &p)//输出
{
    int sz = p.size();
    for (int i = 0; i < sz; i++)
        i == sz - 1 ? printf("%d\n", p[i]) : printf("%d ", p[i]);
}

int main()
{
    fill(dis[0], dis[0] + N * N, inf);//初始化为无穷大
    cin >> n >> m;
    while (m--)//m条边
    {
        int a, b, c;
        cin >> a >> b >> c;
        dis[a][b] = dis[b][a] = c;
    }
    floyd();
    dfs(0);
    output(ans);
    if(ans.size()==n+1)//全部遍历完了
        printf("%d\n", sum);
    else{
        vector<int> rest;
        for (int i = 1; i <= n; i++)
            if (!vis[i])
                rest.push_back(i);
        output(rest);
    }
    return 0;
}

3月考试拉闸了,9月再战
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值