PAT乙级题解总结(更新中)

PAT乙级题解总结

1005 继续(3n+1)猜想 (25分)

传送门
解题思路:

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;


int main()
{
    int n,a[105];
    int v[105]={0};
    cin>>n;
    for(int i=0; i<n; ++i){
        cin>>a[i];
    }

    for(int i=0; i<n; ++i){
        int temp = a[i];
        while(temp!=1){ //开始卡拉兹(Callatz)猜想
            if(temp%2==0){
                temp/=2;
                if(temp<=100&&temp>=1){ //如果在范围内就改变v[]的值
                    v[temp] = 1;
                }

            }
            else{
                temp = temp*3+1;
                temp/=2;
                if(temp<=100&&temp>=1){//如果在范围内就改变v[]的值
                    v[temp] = 1;
                }

            }
        }
    }
    sort(a,a+n);  //因为需要从大到小输出
    int flag = 1;
    for(int i=n-1; i>=0; --i){
        if(!v[a[i]]){ //只要v[a[i]]没被修改,则没有访问过,就要输出
            if(flag) //空格的控制
                cout<<a[i],flag=0;
            else
                cout<<' '<<a[i];

        }

    }
    return 0;
}

这个解法也不错
https://blog.csdn.net/weixin_45617515/article/details/100906672

1008 数组元素循环右移问题 (20分)

直接输出

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;


int main()
{
    int n;
    int m;
    cin>>n>>m;
    int a[105];
    for(int i=0; i<n; ++i)
        cin>>a[i];
    m = m%n;
    for(int i=n-m; i<n; ++i)
        cout<<a[i]<<' ';
    for(int i=0; i<n-m-1; ++i)
        cout<<a[i]<<' ';
    cout<<a[n-m-1];
    return 0;
}

1010 一元多项式求导 (25分)

解题思路:题目没提到数量,应该敏锐地意识到,用while()循环。
或者开个超大的数组。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,m;
    int flag = 0;
    while(cin>>n>>m){
        if(m!=0){
            if(flag!=0)
                cout<<" ";
            cout<<n*m<<' '<<m-1;
            flag = 1;
        }
    }
    if(flag==0)
        cout<<"0 0"<<endl;
    else
        cout<<endl;
    return 0;
}

1014福尔摩斯的约会 (20)

题目入口1014福尔摩斯的约会 (20)

题意:题意刚开始理解错了,他说的应该是两个字符串同一位置的字符是否相等,我理解成,不管在哪个位置,找先后两个相等的字符。
写的时候要注意在循环找到第一组相等的之后,继续查找第二组相等的,而不是重新查找

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#define ll long long

using namespace std;
char wek[10][10] = {"","MON","TUE","WED","THU","FRI","SAT","SUN"};

int main()
{
    string s[4];
    int len[4];
    int week,hour,minute;
    for(int i=0; i<4; ++i){
        cin>>s[i];
        len[i] = s[i].length();
    }
    int i,j;
    int flag = 0;
    for(i=0; i<len[0]&&i<len[1]; ++i){
        if(isupper(s[0][i])&&s[0][i]==s[1][i]){
            week = s[0][i]-'A'+1;
            //if找到后,直接接着后面查找
            for(j=i+1; j<len[0]&&j<len[1]; ++j){
                if(isupper(s[0][j])||s[0][j]<='9'&&s[0][j]>='0'){
                    if(s[0][j]==s[1][j]){
                        if(isupper(s[0][j])){
                            hour = s[0][j]-'A'+10;
                        }
                        else
                            hour = s[0][j]-'0';
                        flag = 1;
                        break;
                    }
                }
            }
            if(flag==1)
                break;
        }
    }
    for(i=0; i<len[2]&&i<len[3]; ++i){
        if(s[2][i]>='a'&&s[2][i]<='z'||s[2][i]>='A'&&s[2][i]<='Z'){
            if(s[2][i]==s[3][i]){
                minute = i;
                break;
            }
        }
    }
    //cout<<s[2][minute]<<' '<<s[3][minute]<<' ';
    printf("%s ",wek[week]);
    printf("%02d:%02d",hour,minute);
    return 0;
}

补一下知识:

 #include <ctype.h>
  int isalpha( int ch );
功能:如果参数是字母字符,函数返回非零值,否则返回零值。
 int isalnum( int ch );
功能:如果参数是数字或字母字符,函数返回非零值,否则返回零值。
 int isdigit( int ch );
功能:如果参数是09之间的数字字符,函数返回非零值,否则返回零值.
 int islower( int ch );
功能:如果参数是小写字母字符,函数返回非零值,否则返回零值。
int isupper( int ch );
功能:如果参数是大写字母字符,函数返回非零值,否则返回零值。

1015德才论(25)

题目入口1015德才论(25)
题解思路:因为分为4类考生,3类考生一定排在4类考生前面,不管分数如何,有一种情况,如果有考生才分很高超过了H, 但是德分低于H,他是一个第4类的考生,但是总分可能比前几类考生高,
所以可以在结构体里加上考生的优先级rankk,这样通过自定义排序可以省去很多麻烦。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
using namespace std;
int n,l,h;
struct student
{
    int num;	//考号
    int mind;  //德分
    int talent;	//才分
    int rankk;	//优先级
}stu[100005];
bool cmp(student a,student b)
{
    int f1 = a.mind+a.talent;
    int f2 = b.mind+b.talent;
    if(a.rankk!=b.rankk)
        return a.rankk < b.rankk; //如果优先级不同,按优先级排序
    else if(f1!=f2)			//如果总分不同,优先级相同,按总分排序
        return f1 > f2;
    else if(a.mind!=b.mind)
        return a.mind > b.mind;	//如果优先级和总分都相等,按德分排
    else
        return a.num < b.num;
}
int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    cin>>n>>l>>h;
    int NUM,MIND,TALENT;
    int k = 0;
    for(int i=0; i<n; ++i){
        cin>>NUM>>MIND>>TALENT;
        if(MIND<l||TALENT<l)
            continue;
        stu[k].num = NUM;
        stu[k].mind = MIND;
        stu[k].talent = TALENT;
        if(stu[k].mind>=h&&stu[k].talent>=h){
            stu[k].rankk = 1;
        }
        else if(stu[k].mind>=h&&stu[k].talent<h){
            stu[k].rankk = 2;
        }
        else if(stu[k].mind<h&&stu[k].talent<h&&stu[k].mind>=stu[k].talent){
            stu[k].rankk = 3;
        }
        else stu[k].rankk = 4;

        k++;
    }
    sort(stu,stu+k,cmp);
    cout<<k<<endl;

    for(int i=0; i<k; ++i){
        cout<<stu[i].num<<' '<<stu[i].mind<<' '<<stu[i].talent<<endl;
    }
    return 0;
}

1017 A除以B (20分)

1017 A除以B (20分)
高精度模拟除法,除数很小,不复杂
基本思想是手算除法的过程,
比如100/2的过程等价于:
1/2, 商为0, 余数为1, 商为0的情况下不能输输出, 要去除前导0
然后余数和下一位: 即0, 组合为1x10+0=10, 就变成10/2, 商为5余数为0,此时输出商数.
然后0和下一位0组合为0*10+0=0, 0/2商为0,余数为0, 此时运算完毕,输出5和0还有余数0

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#define ll long long
using namespace std;
int c[1005];
int main()
{
    string a;
    int b;
    cin>>a>>b;
    int n = a.size();
    int p = 0;
    for(int i=1; i<=n; ++i){
        c[i] = a[i-1]-'0';
    }
    for(int i=1; i<=n; ++i){
        p = p*10 + c[i]; 
        c[i] = p/b;
        p%=b;  
    }
    int id = 1;
    //去前导0
    while(c[id]==0&&id<n) id++;

    for(int i=id; i<=n; i++)
        cout<< c[i];
    cout<<' '<<p;
    return 0;
}

1018 锤子剪刀布 (20分)

1018 锤子剪刀布 (20分)
模拟题,一点一点做

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#define ll long long
using namespace std;
int main()
{
    int n;
    cin>>n;
    int a[3]={0},b[3]={0}; //胜平负的个数
    int v1[3] = {0},v2[3] = {0};  //记录甲乙获胜最多的手势
    //v1[0]代表锤子、v1[1]代表剪刀、v2[2]代表布  的获胜次数
    //v2同理
    for(int i=0; i<n; ++i){
        char c1,c2;
        cin>>c1>>c2;
        if(c1=='C'&&c2=='J'||c1=='B'&&c2=='C'||c1=='J'&&c2=='B'){
            if(c1=='C')
                v1[0]++;
            else if(c1=='J')
                v1[1]++;
            else
                v1[2]++;
            a[0]++;
            b[2]++;
        }
        else if(c1==c2){
            a[1]++;
            b[1]++;
        }
        else {  
            if(c2=='C')
                v2[0]++;
            else if(c2=='J')
                v2[1]++;
            else
                v2[2]++;
            a[2]++;
            b[0]++;
        }
    }
    cout<<a[0]<<' '<<a[1]<<' '<<a[2]<<endl;
    cout<<b[0]<<' '<<b[1]<<' '<<b[2]<<endl;
    int k = 0;
    int t = 0;
    for(int i=0; i<3; ++i){
        if(k<v1[i]){
            t = i;
            k = v1[i];
        }
        else if(k==v1[i]){
            if(i==2){  //如果解不唯一,则输出按字母序最小的解。
                t = i;
                k = v1[i];
            }
            else if(t!=3&&i==0){  
                t = i;
                k = v1[i];
            }
        }
    }
    if(t==0)
        cout<<'C';
    else if(t==1) cout<<'J';
    else cout<<'B';
    cout<<' ';

    k = t = 0;
    for(int i=0; i<3; ++i){
        if(k<v2[i]){
            t = i;
            k = v2[i];
        }
        else if(k==v2[i]){  //如果解不唯一,则输出按字母序最小的解。
            if(i==2){  
                t = i;
                k = v2[i];
            }
            else if(t!=3&&i==0){
                t = i;
                k = v2[i];
            }
        }
    }
    if(t==0)
        cout<<'C';
    else if(t==1) cout<<'J';
    else cout<<'B';
    cout<<endl;
    return 0;
}

1020 月饼 (25分)

1020 月饼 (25分)
题解思路:以单价rankk为标准对商品进行排序,从头往后取


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>

#define ll long long
using namespace std;

struct goods
{
    int stock;	//库存
    int price;	//总价
    double rankk;  //单价
}s[1005];

bool cmp(struct goods a,struct goods b)
{
    return a.rankk > b.rankk;
}
int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    int n,need;
    cin>>n>>need;
    for(int i=0; i<n; ++i){
        cin>>s[i].stock;
    }
    for(int i=0; i<n; ++i){
        cin>>s[i].price;
    }
    for(int i=0; i<n; ++i){
        s[i].rankk = s[i].price*1./s[i].stock;  
    }
    sort(s,s+n,cmp);
    double temp = 0;
    int k = 0; //temp是收益
    while(need>0){
        if(need>=s[k].stock){
            need -= s[k].stock;
            temp += s[k].price;
        }
        else {
            temp += need * s[k].rankk;
            need = 0;
        }
        k++;
    }
    printf("%.2lf\n",temp);
    return 0;
}

1021 个位数统计 (15分)

1021 个位数统计 (15分)
用map<char,int>来存储记录每位出现的次数,map会自动根据第一个参数char的大小进行排序,然后用迭代器进行遍历输出就行


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#define ll long long
using namespace std;
map<char,int> mp;
map<char,int>::iterator t;
int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    string s;
    cin>>s;
    for(int i=0; i<s.size(); ++i){
        mp[s[i]]++;
    }
    for(t=mp.begin(); t!=mp.end(); ++t){
        cout<<t->first<<':'<<t->second<<endl;
    }
    return 0;
}

1022 D进制的A+B (20分)

1022 D进制的A+B (20分)
解题思路:因为这个题并不是任意进制转换,是10进制转某进制,可以用栈模拟转换进制的过程,而且贼简单。注意要判断a+b为0的情况,不然会wa一个点
简单方法


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>

#define ll long long
using namespace std;

stack<int> s;
int main()
{
    ll a,b,c;
    int d;
    cin>>a>>b>>d;
    c = a + b;
    if(c==0)  //判断a+b为0的情况
        cout<<"0";
    while(c>0){
        s.push(c % d);
        c /= d;
    }
    while(!s.empty()){
        cout<<s.top();
        s.pop();
    }

    return 0;
}

刚开始想的复杂了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>

#define ll long long
using namespace std;
 void conversion(char s[],char s2[],long d1,long d2) 
  //d1进制转成d2进制,s[]为原数,s2[]为转换后的,可以实现任意进制转换
{
  long i,j,t,num;
  char c;
  num=0;
  for (i=0;s[i]!='\0';i++)
  {
  if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;
      num=num*d1+t;
      }
    i=0;
    while(1)
      {
      t=num%d2;
      if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;
      num/=d2;
      if (num==0) break;
      i++;
      }
    for (j=0;j<=i/2;j++)
    //翻转数组,因为进制转换的余数倒序后就是进制转换的结果
      {c=s2[j];s2[j]=s2[i-j];s2[i-j]=c;}
    s2[i+1]='\0';
}
char a[100],b[100];

int main()
{
    ll A,B;
    long k;
    cin>>A>>B>>k;
    ll c = A + B;
    int t = 0;
    if(c==0){
        cout<<0<<endl;
        return 0;
    }
    while(c > 0){  //将c变为char数组
        a[t++] = c % 10+'0';
        c /= 10;
    }
    for(int i=0,j=t-1; i<j; ++i,--j){  
    //因为从个位开始取余,所以应该翻转数组后才是原数
        char temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    //cout<<a<<endl;
    conversion(a,b,10,k);  //进制转换

    cout<<b<<endl;
    return 0;
}

1027 打印沙漏 (20分)

1027 打印沙漏 (20分)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#include<iomanip>
#define ll long long
using namespace std;

int a[1001];
int main()
{
    a[0] = 0;
    a[1] = 1;
    for(int i=2; i<600; ++i){ 
     // 用等差数列公式求得总的需要使用的数
     // 下标 i 代表上半部分的列数,a[i]代表需要使用的符号总数
        a[i] = (1 + 1+2*(i-1))*i - 1;
    }
    int n,k,ans = 0;
    char c;
    cin>>n>>c;
    int i;
    for(i=0; a[i]<n; ++i){  //找到最多的

    }
    if(a[i]==n){ //看下能剩下多少符号
        k = i;
        ans = 0; //剩下0个
    }
    else{
        k = i-1;
        ans = n - a[k]; //剩下n-a[k]个
    }

    for(int i=0; i<k*2-1; ++i){
        int t1,t2;
        if(i<k){ //计算数量,这里需要找规律
            t1 = ((k-i)-1)*2+1;
            t2 = i;
        }

        else{
            t1 = ((i-k)+1)*2+1;
            t2 = 2*k-1-i-1;
        }
        for(int j=0; j<t2; ++j)  //输出空格
            cout<<' ';
        //if(i!=k*2-2)
           // cout<<' ';
        for(int j=0; j<t1; ++j){   //输出字符
            cout<<c;
        }

        cout<<endl;
    }

    cout<<ans<<endl;
    return 0;
}

1028 人口普查 (20分)

1028 人口普查 (20分)
在输入过程中判断日期是否合理,不合理直接跳过

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#include<iomanip>
#define ll long long
using namespace std;


struct node
{
    string name;
    int year,month,day;
}a[100005];
bool cmp(struct node a,struct node b)
{
    if(a.year!=b.year)
        return a.year < b.year;
    else if(a.month!=b.month)
        return a.month < b.month;
    else
        return a.day < b.day;
}

int main()
{
    int n;
    cin>>n;
    string time,name;
    int year,month,day;
    int k = 0;
    for(int i=0; i<n; ++i){
        cin>>name;
        cin>>time;
        year = month = day = 0;
        for(int i=0; i<4; ++i){
            year = year * 10 + time[i] - '0';
        }
        for(int i=5; i<=6; ++i){
            month = month * 10 + time[i] - '0';
        }
        for(int i=8; i<=9; ++i){
            day = day * 10 + time[i] - '0';
        }
        //cout<<year<<' '<<month<<' '<<day;
        if(year<1814 || year>2014){  //不符合要求的直接跳过不输入数组
            continue;
        }
        else if(year==1814 && month<=9 && day<6){
            continue;
        }
        else if(year==2014 && month>=9 && day>6){
            continue;
        }
        a[k].name = name;
        a[k].year = year;
        a[k].month = month;
        a[k++].day = day;
    }
    sort(a,a+k,cmp);

    cout<<k<<' ';
    cout<<a[0].name<<' '<<a[k-1].name;
    return 0;
}

1029 旧键盘 (20分)

1029 旧键盘 (20分)
因为要记录某个字符是否已经计入,所以我用map<char,int>来实现记录的功能。
其中英文字母只输出大写,每个坏键只输出一次。题目保证至少有 1 个坏键。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#include<iomanip>
#define ll long long
using namespace std;

map<char,int> mp;
int main()
{
    char s1[100],s2[100];
    cin>>s1;
    cin>>s2;
    int i = 0,j = 0;
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    for( ; i<len1; ++i){
        if(s1[i]==s2[j]){
            j++;
        }
        else if(s1[i]!=s2[j] || s2[j]=='\0'){
            if(islower(s1[i])){
                if(mp[s1[i]-'a'+'A']!=1){
                    cout.put(s1[i]-'a'+'A');
                    mp[s1[i]-'a'+'A'] = 1;
                }
            }
            else if(mp[s1[i]]!=1){
                cout<<s1[i];
                mp[s1[i]] = 1;
            }
        }
    }
    return 0;
}

1030 完美数列 (25分)

1030 完美数列 (25分)
先把数字排序,如果正向扫描枚举最小值,然后从头找数列的个数会超时。
那么我正向枚举最小值,然后从后往前找,只要大于 m* p,就一直往前,直到找到一个小于等于m* p的数,用他的下标和最小值的下标,来计算数列中数的个数,这样时间快了,但是还是wa一个点,我们加一个判断如果 p * m已经大于a[n-1],那么如果最小值继续扩大,数列中数字个数只会减小了,所以直接执行一步跳出循环,AC

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<time.h>
#include<vector>
#include<iomanip>
#define ll long long
using namespace std;

int n,p;
int a[100005];

int main()
{

    scanf("%d%d",&n,&p);
    for(int i=0; i<n; ++i){
        scanf("%d",&a[i]);
    }
    sort(a,a+n);
    int ans = 0;
    int temp = 0;
    for(int i=0; i<n; ++i){
        //temp = 1;
        ll t2 = (ll)p * a[i];
        if(t2 <= a[n-1]){  //加一个判断 AC
            int j;
            for(j=n-1; j>i && a[j]>t2; --j)  //从后往前找
                ;
            temp = j - i + 1;
            ans = max(ans,temp);
        }
        else{
            ans = max(ans,n-1-i+1); //记得判断
            break;
        }
    }
    printf("%d\n",ans);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葛济维的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值