2020春季 pat 乙级真题 答案 (2020-07-25)

2020春季 pat 乙级真题以及答案(99分)

第三题 由于粗心大意 在写的时候忘记了要把结果的前导0去掉 导致我扣掉一分QAQ 有点难过
今年受疫情影响 导致这场考试拖了那么久。看题吧!代码要等考完试一周才能拿到,这里先写思路, 到时候我再更新代码

姥姥发布代码了!更新

7-1 对称日 (15分)

2020春季 pat 乙级真题 答案 (2020-07-25)_第1张图片

央视新闻发了一条微博,指出 2020 年有个罕见的“对称日”,即 2020 年 2 月 2 日,按照 年年年年月月日日 格式组成的字符串 20200202 是完全对称的。

给定任意一个日期,本题就请你写程序判断一下,这是不是一个对称日?

输入格式:
输入首先在第一行给出正整数 N(1

一月:Jan
二月:Feb
三月:Mar
四月:Apr
五月:May
六月:Jun
七月:Jul
八月:Aug
九月:Sep
十月:Oct
十一月:Nov
十二月:Dec

Day 是月份中的日期,为 [1, 31] 区间内的整数;Year 是年份,为 [1, 9999] 区间内的整数。

输出格式:
对每一个给定的日期,在一行中先输出 Y 如果这是一个对称日,否则输出 N;随后空一格,输出日期对应的 年年年年月月日日 格式组成的字符串。

输入样例:

5
Feb 2, 2020
Mar 7, 2020
Oct 10, 101
Nov 21, 1211
Dec 29, 1229

输出样例:

Y 20200202
N 20200307
Y 01011010
Y 12111121
N 12291229

解题思路:
我的思路是先把月份映射成数字 然后再把数字转成string 由于存在一些特殊情况 譬如101 10 10得有前导0 所以直接定一string 然后往里面填充0 再进行判断对称

#include
#include
#include
using namespace std;
int mon(string s){
    string mm[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
    for(int i=0;i<12;++i){
        if(s==mm[i])return i+1;
    }
    return 0;
}
bool judge(string str){
    int len=str.size()-1;
    for(int i=0;i<=len/2;++i){
        if(str[i]!=str[len-i])return false;
    }
    return true;
}
int main()
{
    int year,day,n;
    scanf("%d",&n);
    while(n--){
        string ans,s;
        cin>>s;
        scanf("%d, %d",&day,&year);
        int tmp=year*10000+mon(s)*100+day;
        ans=to_string(tmp);
        while(ans.size()<8) ans="0"+ans;
        printf(judge(ans)?"Y %s\n":"N %s\n",ans.c_str());
    }
    return 0;
}

7-2 超标区间 (20分)

2020春季 pat 乙级真题 答案 (2020-07-25)_第2张图片

上图是用某科学研究中采集的数据绘制成的折线图,其中红色横线表示正常数据的阈值(在此图中阈值是 25)。你的任务就是把超出阈值的非正常数据所在的区间找出来。例如上图中横轴 [3, 5] 区间中的 3 个数据点超标,横轴上点 9 (可以表示为区间 [9, 9])对应的数据点也超标。

输入格式:
输入第一行给出两个正整数 N(≤10^​4 )和 T(≤100),分别是数据点的数量和阈值。第二行给出 N 个数据点的纵坐标,均为不超过 1000 的正整数,对应的横坐标为整数 0 到 N−1。

输出格式:
按从左到右的顺序输出超标数据的区间,每个区间占一行,格式为 [A, B],其中 A 和 B 为区间的左右端点。如果没有数据超标,则在一行中输出所有数据的最大值。

输入样例 1:

11 25
21 15 25 28 35 27 20 24 18 32 23

输出样例 1:

[3, 5]
[9, 9]

输入样例 2:

11 40
21 15 25 28 35 27 20 24 18 32 23

输出样例 2:

35

解题思路:
可以使用两个变量 一个直接记录最大值 还有一个是记录第一次出现的高于阈值的数字 然后转换一下状态 再找出第一次小于阈值的数字,类似于状态机转换过程 还有 最后要做一个判断 因为可能存在 最后一个数字高于阈值
代码:

#include
int data[100000];
int main()
{
    int t,n,flag=1,flag2=0,maxn=-1;
    scanf("%d %d",&n,&t);
    for(int i=0,tmp;i<n;++i){
        scanf("%d",&tmp);
        data[i]=tmp;
    }
    for(int i=0;i<n;++i){
        if(maxn<data[i])maxn=data[i];
        if(data[i]>t && flag==1){
                printf("[%d, ",i);
                flag=2;
                flag2=1;
        }
        if(data[i]<=t && flag==2){
            printf("%d]\n",i-1);
            flag=1;
        }
    }
    if(flag==2)printf("%d]\n",n-1);
    if(flag2==0)printf("%d\n",maxn);
    return 0;
}

7-3 钱串子的加法 (20分)

2020春季 pat 乙级真题 答案 (2020-07-25)_第3张图片

人类习惯用 10 进制,可能因为大多数人类有 10 根手指头,可以用于计数。这个世界上有一种叫“钱串子”(学名“蚰蜒”)的生物,有 30 只细长的手/脚,在它们的世界里,数字应该是 30 进制的。本题就请你实现钱串子世界里的加法运算。

输入格式:
输入在一行中给出两个钱串子世界里的非负整数,其间以空格分隔。

所谓“钱串子世界里的整数”是一个 30 进制的数字,其数字 0 到 9 跟人类世界的整数一致,数字 10 到 29 用小写英文字母 a 到 t 顺次表示。

输入给出的两个整数都不超过 10^5位。

输出格式:
在一行中输出两个整数的和。注意结果数字不得有前导零。

输入样例:

2g50ttaq 0st9hk381

输出样例:

11feik2ir

解题思路:
就是这个题 切记考试时候 认真 细心、我是采用模拟加法的过程 最后调试时候停留在这题 所以我把代码带了出来。模拟的思路很简单 还有记得 末尾的特判 因为可能加完之后 还存在进位的情况 所以 判断一下 然后输出

#include
using namespace std;
int main()
{
    string s1,s2,res;
    cin>>s1>>s2;
    while(s1.size()>1 && s1[0]=='0')s1.erase(s1.begin());
    while(s2.size()>1 && s2[0]=='0')s2.erase(s2.begin());
    int len1=s1.size(),len2=s2.size();
    int i=len1-1,j=len2-1,flag=0;//flag ½èλ
    while(i>=0 || j>=0){
        int a=0,b=0;
        if(i>=0 && isalpha(s1[i]))a=10+s1[i]-'a';
        else if(i>=0 && isdigit(s1[i]))a=s1[i]-'0';
        if(j>=0 && isalpha(s2[j]))b=10+s2[j]-'a';
        else if(j>=0 && isdigit(s2[j]))b=s2[j]-'0';
        char rec;
        int rei=a+b+flag;
        flag=0;
        if(rei>=30){
            flag=1;
            rei-=30;
        }
        if(rei<10)rec=rei+'0';
        else if(rei>=10)rec=rei-10+'a';
        res=rec+res;
        if(i>=0)i--;
        if(j>=0)j--;
    }
    if(flag)res="1"+res;
    cout<<res<<endl;
    return 0;
}

如果有问题交流咨询,可以加入QQ群:673852347

7-4 全素日 (20分)

2020春季 pat 乙级真题 答案 (2020-07-25)_第4张图片

以上图片来自新浪微博,展示了一个非常酷的“全素日”:2019年5月23日。即不仅20190523本身是个素数,它的任何以末尾数字3结尾的子串都是素数。

本题就请你写个程序判断一个给定日期是否是“全素日”。

输入格式:
输入按照 yyyymmdd 的格式给出一个日期。题目保证日期在0001年1月1日到9999年12月31日之间。

输出格式:
从原始日期开始,按照子串长度递减的顺序,每行首先输出一个子串和一个空格,然后输出 Yes,如果该子串对应的数字是一个素数,否则输出 No。如果这个日期是一个全素日,则在最后一行输出 All Prime!。

输入样例 1:

20190523

输出样例 1:

20190523 Yes
0190523 Yes
190523 Yes
90523 Yes
0523 Yes
523 Yes
23 Yes
3 Yes
All Prime!

输入样例 2:

20191231

输出样例 2:

20191231 Yes
0191231 Yes
191231 Yes
91231 No
1231 Yes
231 No
31 Yes
1 No

解题思路:
看了下 输出结果的格式 认为使用string来处理比较好 因为呢 有前导0这样的情况存在 如果直接变成数字 就有点麻烦了 使用string转int 有现成函数 stoi 然后质数判断 本题数量不大 直接判断即可

#include
#include
using namespace std;
bool judge(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 flag=0,tmp;
    string str;
    cin>>str;
    while(str.size()>0){
        tmp=stoi(str);
        if(!judge(tmp)){
            flag=1;
            printf("%s No\n",str.c_str());
        }
        else printf("%s Yes\n",str.c_str());
        str.erase(str.begin());
    }
    if(flag==0)cout<<"All Prime!"<<endl;
    return 0;
}

如果有问题交流咨询,可以加入QQ群:673852347

7-5 裁判机 (25分)

有一种数字游戏的规则如下:首先由裁判给定两个不同的正整数,然后参加游戏的几个人轮流给出正整数。要求给出的数字必须是前面已经出现的某两个正整数之差,且不能等于之前的任何一个数。游戏一直持续若干轮,中间有写重复或写错的人就出局。

本题要求你实现这个游戏的裁判机,自动判断每位游戏者给出的数字是否合法,以及最后的赢家。

输入格式:
输入在第一行中给出 2 个初始的正整数,保证都在 [1,10
​5
​​ ] 范围内且不相同。

第二行依次给出参加比赛的人数 N(2≤N≤10)和每个人都要经历的轮次数 M(2≤M≤10^3​ )。

以下 N 行,每行给出 M 个正整数。第 i 行对应第 i 个人给出的数字(i=1,⋯,N)。游戏顺序是从第 1 个人给出第 1 个数字开始,每人顺次在第 1 轮给出自己的第 1 个数字;然后每人顺次在第 2 轮给出自己的第 2 个数字,以此类推。

输出格式:
如果在第 k 轮,第 i 个人出局,就在一行中输出 Round #k: i is out.。出局人后面给出的数字不算;同一轮出局的人按编号增序输出。直到最后一轮结束,在一行中输出 Winner(s): W1 W2 … Wn,其中 W1 … Wn 是最后的赢家编号,按增序输出。数字间以 1 个空格分隔,行末不得有多余空格。如果没有赢家,则输出 No winner.。

输入样例 1:

101 42
4 5
59 34 67 9 7
17 9 8 50 7
25 92 43 26 37
76 51 1 41 40

输出样例 1:

Round #4: 1 is out.
Round #5: 3 is out.
Winner(s): 2 4

输入样例 2:

42 101
4 5
59 34 67 9 7
17 9 18 50 49
25 92 58 1 39
102 32 2 6 41

输出样例 2:

Round #1: 4 is out.
Round #3: 2 is out.
Round #4: 1 is out.
Round #5: 3 is out.
No winner.

解题思路:
这题也是甲级里面的题 我当时做的时候 使用了vector + 大数组的处理方式,因为一开始我使用了set判断但是 有一个测试点 一直超时(肯定超时 是n*n的级别,n是已经构造好的数字集合) 所以 想着改成了大数组 一方面判断key是否存在,一方面判 number-key是否存在 这样只需要遍历一次集合即可,这样时间复杂度降低至O(n)。我这里说的是判定时候的耗时 没说整体的时间复杂度

#include
#include
#include
using namespace std;
int tags[100010];
int main()
{
    int n,m;
    int a,b;
    vector<int>done;
    vector<vector<int> >stu;
    scanf("%d %d",&a,&b);
    done.push_back(a);
    done.push_back(b);
    tags[a]=tags[b]=1;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;++i){
        vector<int>vect;
        for(int j=0,tmp;j<m;++j){
            scanf("%d",&tmp);
            vect.push_back(tmp);
        }
        stu.push_back(vect);
    }
    vector<int>flag(n,1);
    int left=n;
    for(int i=0;i<m && left;++i){
        for(int j=0;j<n && left;++j){
            if(flag[j]==0)continue;//如果已经out了 就不必再判断了

            int out=0;
            if(tags[stu[j][i]]) out=1;
            else{
                for(auto it=done.begin();it!=done.end();++it){
                    if((*it)-stu[j][i]>0 && tags[ (*it)-stu[j][i] ]){
                        out=2;
                        break;
                    }
                }
            }
            if(out!=2){
                left--;
                flag[j]=0;
                printf("Round #%d: %d is out.\n",i+1,j+1);
            }
            else{
                done.push_back(stu[j][i]);
                tags[stu[j][i]]=1;
            }
        }
    }
    if(left==0)printf("No winner.\n");
    else{
        printf("Winner(s):");
        for(int i=0;i<n;++i)if(flag[i])printf(" %d",i+1);
    }
    return 0;
}

如果有问题交流咨询,可以加入QQ群:673852347

你可能感兴趣的:(PAT)