2021年春季 PAT乙级(复盘)

前言

大一菜鸡,最后是82分,好像是87名。 最终排名90 。(本来可以满分的)
除了第四题其他的都AC了,第四题就混了一点分。。。


7-1 打印三角形拼图 (15 分)

一个正方形可以用两个等边直角三角形拼出来。给定正方形的边长、两个三角形和对角线所用的符号,请你打印出这两个三角形拼出的正方形。

输入格式:

输入在一行中给出一个正整数 L L L 2 ≤ L ≤ 100 2 ≤ L ≤ 100 2L100,为正方形的边长),同时给出打印上三角形、下三角形、对角线所用的字符。数字和字符间以一个空格分隔。

输出格式:

按输入要求打印这两个三角形拼出的正方形。

输入样例:

6 a b -

输出样例:

-aaaaa
b-aaaa
bb-aaa
bbb-aa
bbbb-a
bbbbb-

题意解读: 就是一个简单的模拟题目,打印一下图形而已,首先用一个二维矩阵存一下最终的输出结果,然后打印出来就好。对角线是 q [ i ] [ i ] q [ i ] [ i ] q[i][i] ,然后两个for循环填入a b两种数据就可以辣

代码:

#include <iostream>
using namespace std;
int main () {
    int n;
    char a , b , c;
    cin >> n >> a >> b >> c;
    string q[n][n];
    for (int i = 0 ; i < n ; i ++) {
        q[i][i] = c;        //对角线
        for (int j = i + 1 ; j < n ; j ++) q[i][j] = a;     //a的位置
        for (int j = 0 ; j < i ; j ++) q[i][j] = b;     //b的位置
    }
    for (int i = 0 ; i < n ; i ++) {
        for (int j = 0 ; j < n ; j ++) cout << q[i][j];
        cout << endl;
    }
    return 0;
}

//输入结果
6 a b -

//输出结果
-aaaaa
b-aaaa
bb-aaa
bbb-aa
bbbb-a
bbbbb-

总结:这个题难度不大,而且也没啥坑点,几分钟就写完了



7-2 赌马 (20 分)

题目: 听说香港中文大学有一个教授开发了一个“投注方程式”来赌马,三个赛季就赚了 5000 万港币。现在请你来开发一个简单的赌马程序:假设开赛若干分钟之内都可以下注,而你可以准确获得截止时间最后一刻每匹马到终点的距离和它的瞬时速度,这样你就可以算出每匹马到达终点还需要多少时间。每次下注预测的前三名,中奖的几率是不是很大啊~

输入格式: 输入在第一行中给出一个正整数 3 ≤ N ≤ 1 0 4 ​ ​ 3 ≤ N ≤ 10^4​​ 3N104 ,是参赛的马匹数量(虽然有点夸张)。随后 N N N 行,每行按以下格式给出:

马的编号 到终点的距离 瞬时速度

其中马的编号是 1 到 10的四次方​​之间的整数,每匹马的编号是唯一无重复的;到终点的距离是 1 到 10的三次方​​之间的整数,单位为“米”;瞬时速度是 1 到 20 之间的整数,单位为“米/秒”。

输出格式:
在一行中按到达终点的顺序输出预测的前三名马的编号。如果有并列,按编号递增序取前面的输出。
编号间以 1 个空格分隔,行首尾不得有多余空格。

案例输入

6
886 500 12
6688 600 18
8866 700 15
2333 500 15
1234 650 11
6666 375 9

输出样例:

2333 6688 886

思路: 创建一个结构体node来保存马的id跟到终点的时间,然后写一个cmp函数来排序就好了

代码子:

#include <iostream>
#include <algorithm>
using namespace std;
struct node {       //保存id 跟 时间
    int id;
    float time;        
};
bool cmp (node a , node b) {
    return a.time != b.time ? a.time < b.time : a.id < b.id;    
}       //当时间不相等的时候按照时间递增排序 否则按照id递增排序
int main () {
    int n;
    cin >> n;
    node q[n];
    for (int i = 0 ; i < n ; i ++) {
        int a , b , c;
        cin >> a >> b >> c;
        q[i].id = a;
        q[i].time = float(b) / float(c); 
    }
    sort (q , q + n , cmp);
    for (int i = 0 ; i < 3 ; i ++) {
    	if (i != 0) cout << " ";
    	cout << q[i].id;
	} cout << endl;
    return 0;
}

总结: 这个题就是一个比较简单的结构体排序问题了,当时也是一遍过的hhh



7-3 拼题 A 是真爱 (20 分)

题目: 如果一个人在一段话里很多次提到 pintia,那对拼题 A 就是真爱啦~ 本题就请你检查一下给定的文字中出现了几次 pintia。
输入格式:
输入在一行中给出一个总长度不超过 10的四次方字符的非空字符串,由英文字母和标点符号 , 和 . 以及空格组成,以一个回车结束。

输出格式:
首先在第一行输出给定文字中出现了多少次 pintia 或 Pintia。

如果一次都没有,在第二行输出 wu gan(无感);如果有但不超过 3 次,输出 you ai(有爱);如果超过了 3 次,输出 zhen ai la(真爱啦)。

注意只有当 pintia 作为完整独立的词出现的时候才算一次,即它必须跟其他文字以空格或者标点符号分开。



题目大意: 给一串字符串只包含空格 , 英文字母 , ‘,’ , 以及 ‘.’这些字符。统计一下独立的pintia或者Pintia的数目 (独立的意思就是pintia前面后面都不能是英文字符)

假如有0个则输出wu gan
假如有<= 3个则输出you ai
假如有大于三个则输出zhen ai la

输出格式:
pintia (Pintia)的总数
数量对应的字符串

案例输入(大概):
案例一
输入:

This is a pintiatest.

输出:

0
wu gan


案例二
输入:

This is apintia test. Hey I love pintia a

输出:

1
you ai


案例三

输入:

This is apintiatest. Hey I love pintia, really zhen ai pintia la,pintia is my favorite place to go. Come on visit Pintia.

输出:

4
zhen lai la



思路: 因为是一个完整句子所以假如pintia出现在第一个的话特殊判断一下,否则就遇到非英文字符a[ i ] ,就将后六个字符一起拿出来跟pintia 或者 Pintia 比较一下 , 然后a[i + 7]假如也不是英文字符就是一个独立的pintia了

代码子:

#include <iostream>
#include <string>
using namespace std;
int main () {
    string a;
    string up = "Pintia" , low = "pintia";		//大小写的字符串先写出来等下再比较
    int cnt = 0;
    getline (cin , a);
    int la = a.length();
    for (int i = 0 ; i < la - 6; i ++) {
        if (i == 0 && (a[i] == 'P' || a[i] == 'p')) {	//假如是以pintia开头的话就特殊判断
            if (a.substr(i , 6) == up || a.substr(i , 6) == low && !isalpha(a[i + 6])) 
            	cnt ++;
        }
        else if (!isalpha(a[i])) {	  // 非英文字符就将后六个拿出来比较 
        							//且第七个也不是英文字符的话就能行
            if (a.substr(i + 1, 6) == up || a.substr(i + 1, 6) == low && !isalpha(a[i + 7])) 
            	cnt ++;
        }
    }
    if (cnt == 0) {
        cout << cnt << endl << "wu gan";
    }
    else if (cnt <= 3) {
        cout << cnt << endl << "you ai";
    }
    else cout << cnt << endl << "zhen ai la";
    return 0;
}

总结: 就是一道比较简单的substr函数使用而已,pta题库里面还是比较多的辣



7-4 素数等差数列 (20 分)

这道题是我写了差不多一个半钟都没写出来的很可惜,当时确实脑抽了,暴力枚举都不会写了hhh

这道题,当官方把代码放出来的时候,原来我的思路跟想法都是正确的,但是最后可能又脑抽了,因为一行小小的代码位置放错了,最终跟满分失之交臂。。。挺可惜的hhh。

题目:

2004 年,陶哲轩(Terence Tao)和本·格林(Ben Green)证明了:对于任意大的 n,均存在 n 项全由素数组成的等差数列。例如 { 7,37,67,97,127,157 } 是 n=6 的解。本题就请你对给定的 n 在指定范围内找出一组最大的解。

输入格式:
输入在一行中给出两个正整数:n(≤ 10)为等差素数数列的项数; MAXP (2 ≤ MAXP <= 1e5​​ )为数列中最大素数的上界。

输出格式:
如果解存在,则在一行中按递增序输出等差最大的一组解;若解不唯一,则输出首数最大的一组解。若解不存在,则输出不超过 MAXP 的最大素数。同行数字间以一个空格分隔,行首尾不得有多余空格。



题目大意:
给定n跟p,n为项数 , p为数列中最大的素数的上限(2 <= p <= 1e5)假如有n项素数等差数列,就返回首项最大的那一组。假如没有就返回最靠近p的素数。

案例输入1:

6 200

案例输出:

7 37 67 97 127 157

案例输入2:

5 1000

案例输出:

23 263 503 743 983

案例输入3:

10 200

案例输出:

199



思路: 首先打印一个素数表(埃氏筛法),然后将小于p的素数存在一个vector中,然后从后向前开始枚举,二重for循环, 那么公差也就是v[ i ] - v[ j ] 了,此时再枚举一下有多少个能符合此公差的。


具体实现:
首先用埃氏筛法将小于MAXP的所有素数都保存在vector v中,然后从后往前两重for循环开始向前枚举。那么公差也就是 v[ i ] - v[ j ] , 然后再在此时创建一个vector ans,将每一个满足等差数列的质数保存下来。假如ans的size等于n那么就输出答案,结束程序;否则当枚举完了之后还没找到就找到最靠近MAXP的素数。


思路看起来挺对的我觉得,但是我代码敲出来就是错的,不知道是哪一个小点除了bug hhh
结果真的就是这么一点小bughhhh

后来在网上看到一个证明就是说 1 - 10里面的等差素数排列都是以三十为公差的(可以自行证明一下),要是想得出来的话应该就能大幅度减少时间了把hhh。


我考试的错误代码(大家可以找找错误,很小的一个错误)

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int primearr [N];
bool isprime (int a) {
    int n = sqrt(a);
    if (a <= 1) return false;
    for (int i = 2 ; i <= n ; i ++)
        if (a % i == 0) return false;
    return true;
}
int findprime (int a) {
    int ans = 0;
    for (int i = a ; i >= 0 ; i --)
        if (isprime(i)) {
            ans = i;
            break;
        }
    return ans;
}
int main () {
    int n , p;
    vector <int > v;
    cin >> n >> p;
    for (int i = 2 ; i <= p ; i ++) if (isprime(i)) primearr[i] = 1 , v.push_back(i);
    int vn = v.size();      //在p范围内的素数
    
    for (int i = vn - 1 ; i >= 0 ; i --) {
        vector <int > ans;		//注意此处。。。。。
        for (int j = i - 1; j >= 0 ; j --) {
            ans.push_back (v[i]);       
            ans.push_back (v[j]);       
            int gongcha = v[i] - v[j];
            int tt = v[j];
            for (int k = j - 1; k >= 0 ; -- k) {
                if (v[k] + gongcha == tt) {
                    ans.push_back(v[k]);
                    tt = v[k];
                }
            }
            reverse (ans.begin() , ans.end());
            if (ans.size() == n) {
                for (int ii = 0 ; ii < n ; ii ++) {
                    if (ii != 0) cout << " ";
                    cout << ans[ii];
                }
                return 0;
            }
        }
    }
    cout << findprime (p);
    return 0;
}

这里附上别人大神的代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+5;
int prime[N],ans[20];
int n,m,lim;
vector<int> v;

void setv() {
    prime[0]=prime[1]=1;
    for(int i=2;i<=m;i++)
        if(!prime[i]){
            v.push_back(i);
            for(int j=i+i;j<=m;j+=i)
                prime[j]=1;
        }
}

bool judge(int i,int j){
    int dif=v[i]-v[j];
    for(int k=0;k<n;k++)
        if(v[i]-dif*k<0||prime[v[i]-dif*k])
            return false;
    return true;
}

int main(){
    scanf("%d%d",&n,&m);
    lim=m/n;
    setv();
    int dif=-1;
    for(int i=v.size()-1;i>=0;i--){
        for(int j=i-1;j>=0;j--)
            if((v[i]-v[j]>dif||(v[i]-v[j]==dif&&v[i]-dif*(n-1)>ans[0]))&&judge(i,j)){
                dif=v[i]-v[j];
                int cnt=0;
                for(int k=n-1;k>=0;k--){
                    ans[k]=v[i]-dif*cnt;
                    cnt++;
                }
            }
    }
    if(dif!=-1)
        for(int i=0;i<n;i++)
            printf("%d%c",ans[i],i==n-1? '\n':' ');
    else
        printf("%d\n",v[v.size()-1]);

    return 0;
}

总结:

7-5 实验室使用排期 (25 分)

题目大意: 给定n个人,以及每个人的预约时间:包括进入时间,出去时间。
问一天最多能排多少个人?(注意,不能两个人同时再实验室,也就是一个人出去了才能再进去下一个人)

输入案例:

7

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

输出案例:

5

案例解释:输入案例中最后两个人不进去就是最大可以进入的人

思路: 典型的贪心算法!!!首先先按照进入时间来排序,然后从头开始遍历一次,假如下一个人的进入时间>=当前这个进入的人的出去时间,那么就cnt ++
然后再从后往前遍历一次,下一个进去的人的出去时间要 <= 当前进去的人的进入时间
然后两次取最优解也就是最大值就行了

代码子(敲了有四十多分钟了hhh):

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
struct node {
    string ft;		//ft代表fronttime 表示进入时间
    string bt;		//bt代表backtime 表示出来时间
};
bool cmp (node a , node b) {
    return a.ft != b.ft ? a.ft < b.ft : a.bt < b.bt;
}		//按照进入时间递增排序
int main () {
    int n;
    cin >> n;
    string mxtime = "23:59:59";
    string mntime = "00:00:00";
    node q[n];
    int sum = 0;
    while (n --) {
        string a , b;
        cin >> a >> b;
        if (a < mntime || b > mxtime) continue;
        else {		//因为题目说每次在实验室的时间是一天内 
            q[sum].ft = a;		//所有怕有超过一天的错误数据因此为了以防万一
            q[sum].bt = b;		//重新判断了一次 这下的数据就一定是有效数据了
            sum ++;
        }
    }
    int ans = 0 , cnt = 1;
    string backcrt = q[0].bt;
    for (int i = 0 ; i < sum ; i ++) {		//从头开始遍历
        for (int j = i ; j < sum ; j ++) {
            if (q[j].ft >= backcrt) {
                cnt ++;
                backcrt = q[j].bt;
                i = j;
                break;
            }
        }
        ans = max(cnt , ans);
    }
    string frontcrt = q[sum - 1].ft;
    cnt = 1;
    for (int i = sum - 1; i >= 0 ; i --) {		//从尾开始遍历
        for (int j = i ; j >= 0 ; j --) {
            if (q[j].bt <= frontcrt) {
                cnt ++;
                frontcrt = q[j].ft;
                i = j;
                break;
            }
        }
        ans = max (cnt , ans);		//取得最优解
    }
    cout << ans << endl;
    return 0;
}

总结:
功夫不负有心人,写了四十分钟,压轴题是AC了,看着时间还有一个多小时,以为这次满分有希望了,结果没想到这剩下的一个多小时只得了两分 泪目子。。
只能说挺可惜的,希望下一次再接再厉,明年PAT甲级见。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值