PAT basic level 答案+解题思路+难点 (个人刷题记录)

PAT basic level

使用语言:C++
仅记录一下自己刷题过程的心得体会

永远保持更新(期待更好的解法)
可能有些题没有(那就是我还没做出来,以后会更的!)
欢迎大家与我讨论交流√

1001 害死人不偿命的(3n+1)猜想

题目:
卡拉兹(Callatz)猜想:
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到 n=1。卡拉兹在 1950 年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证 (3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……

我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过 1000 的正整数 n,简单地数一下,需要多少步(砍几下)才能得到 n=1?

** 输入格式:**
每个测试输入包含 1 个测试用例,即给出正整数 n 的值。

输出格式:
输出从 n 计算到 1 需要的步数。

输入样例:
3
输出样例:
5

解题思路:
很普通的一道题。就依照题目的要求,如果是偶数则除以2,是奇数则变为3n+1再除以2,中途用一个变量记录砍的次数,当n=1的时候停止循环并输出次数即可。

值得记下的点:

代码:

#include <stdio.h>
int main()
{
    int n,i,count=0; //count用于计数
    scanf("%d",&n);
    while(n!=1)
    {
        if(n%2==0)
            {n=n/2;count++;}
        else
            {n=(3*n+1)/2;count++;}
    }
    printf("%d",count);
    return 0;

}

1002 写出这个数

题目:
读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字。

输入格式:
每个测试输入包含 1 个测试用例,即给出自然数 n 的值。这里保证 n 小于 10100

输出格式:
在一行内输出 n 的各位数字之和的每一位,拼音数字间有 1 空格,但一行中最后一个拼音数字后没有空格。

输入样例:
1234567890987654321123456789
结尾无空行
输出样例:
yi san wu
结尾无空行

解题思路:
1.本题由于输入数字很大,所以输入类型选择字符串。
2.我的思路是将字符串的每一位都转换为数字,然后累加求和
3.求和后,将sum转换为字符串,然后再对应位置输出拼音(因为再变为字符串就不需要求余取位了,直接从字符串中0的位置开始对应输出即可)

值得记下的点:
利用C++中的strstream进行字符串和数字的类型转换

代码:

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

int main()
{
    string str;
    string num[] = {"ling", "yi", "er", "san", "si",
                      "wu","liu", "qi","ba", "jiu"};//这里只能用双引号
    int a=0;
    string sum;
    cin >> str;
    for(int i=0;i<str.length();i++)
    {
        int temp;
        temp = str[i]-'0';
        a=a+temp;
    }

    strstream ss;
    ss << a;
    ss >> sum;
    int flag=0;
    for(int i=0;i<sum.length();i++)
    {
        int temp;
        temp = sum[i]-'0';
        if(flag==0)
        {
            cout << num[temp];
            flag=1;
            continue;
        }
        else
        {
            cout << " ";
            cout << num[temp];
        }    
    }
    return 0;
}

1003 我要通过!

题目:
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。

得到“答案正确”的条件是:

字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。

输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。

输入样例:
9
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
NO

解题思路:
这题很难!需要转化题目条件来进行判断。
分析条件:
1.字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
翻译:P、T、A三种字符出现的次数相加一定要等于字符串的长度。因此想到设置cnt记下P、T、A的出现次数。

2.任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
翻译:说明P和T仅仅只可以出现一次。二者之间需要有一个A。

3.如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
翻译:P和T之间每增加一个A,字符串最后都需要增加一个A。可以得出P前面字符串长度乘以PT之间字符数目等于T后面字符的数目。

值得记下的点:
主要还是需要翻译题目条件,然后进行判断即可。

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    int n,i;
    scanf("%d",&n);
    while(n--)
    {
        string str;
        cin>>str;
        int posP=0,posT=0;//记录P和T的位置
        int cntP=0,cntA=0,cntT=0;//记录PTA出现的次数
        for(i=0;i<str.length();i++)
        {
            if(str[i]=='P')
            {
                   posP=i;
                   cntP++;
            }
            else if(str[i]=='A')
                   cntA++;
            else if(str[i]=='T')
            {
                   posT=i;
                   cntT++;
            }
        }
        if(cntP+cntA+cntT<str.length()||cntP>1||cntT>1||posT-posP<=1||posP*(posT-posP-1)!=str.length()-posT-1)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;

}

1004 成绩排名

题目:
读入 n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。

输入格式:
每个测试输入包含 1 个测试用例,格式为

第 1 行:正整数 n
第 2 行:第 1 个学生的姓名 学号 成绩
第 3 行:第 2 个学生的姓名 学号 成绩
… … …
第 n+1 行:第 n 个学生的姓名 学号 成绩
其中姓名和学号均为不超过 10 个字符的字符串,成绩为 0 到 100 之间的一个整数,这里保证在一组测试用例中没有两个学生的成绩是相同的。

输出格式:
对每个测试用例输出 2 行,第 1 行是成绩最高学生的姓名和学号,第 2 行是成绩最低学生的姓名和学号,字符串间有 1 空格。

输入样例:
3
Joe Math990112 89
Mike CS991301 100
Mary EE990830 95
输出样例:
Mike CS991301
Joe Math990112

解题思路:
很常规的一道题。创建一个结构体来储存学生的信息,在输入的时候就记下最大值和最小值的下标值,就不需要进行排序了。最后直接输出即可。

值得记下的点:
1.利用结构体
2.输入的同时直接作记录

代码:

#include<stdio.h>
#include<iostream>
using namespace std;
struct Node{
	string name;
	string code;
	int grade;
};
int main()
{
	int n;
	scanf("%d",&n);
	struct Node stu[n];
	int mmax,mmin,tarmax,tarmin;
	for(int i=0;i<n;i++)
	{
		cin>>stu[i].name>>stu[i].code>>stu[i].grade;
		if(i==0)
		{
			mmax=stu[i].grade;
			mmin=stu[i].grade;
			tarmax=tarmin=0;
		}
		else
		{
			if(mmax<stu[i].grade)
			{
				mmax=stu[i].grade;
				tarmax=i;
			}
			if(mmin>stu[i].grade)
			{
				mmin=stu[i].grade;
				tarmin=i;
			}
		}
	}	
	cout<<stu[tarmax].name<<" "<<stu[tarmax].code<<endl;
	cout<<stu[tarmin].name<<" "<<stu[tarmin].code<<endl;	
	return 0;
}

1006 换个格式输出整数

题目:
让我们用字母 B 来表示“百”、字母 S 表示“十”,用 12…n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过 3 位的正整数。例如 234 应该被输出为 BBSSS1234,因为它有 2 个“百”、3 个“十”、以及个位的 4。

输入格式:
每个测试输入包含 1 个测试用例,给出正整数 n(<1000)。

输出格式:
每个测试用例的输出占一行,用规定的格式输出 n。

输入样例 1:
234
输出样例 1:
BBSSS1234
输入样例 2:
23
输出样例 2:
SS123

解题思路:
照题目说的做即可。
百位数上是n则输出n个B
十位数上是n则输出n个S
个位数上是n,则输出123…n(这以用个for循环来写)

值得记下的点:
取位数的方法

代码:

#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    int n,a,b,c,t=1,i;
    scanf("%d",&n);
    a=n%10;
    b=n/10%10;
    c=n/100;
    while(c!=0)
    {
          printf("B");
          c--;
     }
    while(b!=0)
    {
          printf("S");
          b--;
     }
    for(i=0;i<a;i++)
    {
        printf("%d",t);
        t++;
    }
    return 0;

}

1008 数组元素循环右移问题

题目:
在这里插入图片描述
输入格式:
每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0);第2行输入N个整数,之间用空格分隔。

输出格式:
在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

输入样例:
6 2
1 2 3 4 5 6
输出样例:
5 6 1 2 3 4

解题思路:
题目要求是不允许使用另外的数组,一切比较和交换都在数组A中进行。
我想到的思路是把最后一位数储存起来,然后剩余数依次往后挪一位,再把第一位数设为最后一位数即可。
按以上方式循环M次即可完成右移。

代码:

#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    int i,j,temp,N,M,a[1000];
    scanf("%d%d",&N,&M);
    for(i=0;i<N;i++)
        scanf("%d",&a[i]);
    for(i=0;i<M;i++)
    {
        temp=a[N-1];
        for(j=N-1;j>0;j--)
            a[j]=a[j-1];
        a[0]=temp;

    }
    for(i=0;i<N;i++)
    {
        printf("%d",a[i]);
        if(i<N-1)
            printf(" ");
    }
    
    return 0;
}

1071 小赌怡情

题目:
常言道“小赌怡情”。这是一个很简单的小游戏:首先由计算机给出第一个整数;然后玩家下注赌第二个整数将会比第一个数大还是小;玩家下注 t 个筹码后,计算机给出第二个数。若玩家猜对了,则系统奖励玩家 t 个筹码;否则扣除玩家 t 个筹码。

注意:玩家下注的筹码数不能超过自己帐户上拥有的筹码数。当玩家输光了全部筹码后,游戏就结束。

输入格式:
输入在第一行给出 2 个正整数 T 和 K(≤ 100),分别是系统在初始状态下赠送给玩家的筹码数、以及需要处理的游戏次数。随后 K 行,每行对应一次游戏,顺序给出 4 个数字:

n1 b t n2

其中 n1 和 n2 是计算机先后给出的两个[0, 9]内的整数,保证两个数字不相等。b 为 0 表示玩家赌小,为 1 表示玩家赌大。t 表示玩家下注的筹码数,保证在整型范围内。

输出格式:
对每一次游戏,根据下列情况对应输出(其中 t 是玩家下注量,x 是玩家当前持有的筹码量):
玩家赢,输出 Win t! Total = x.;
玩家输,输出 Lose t. Total = x.;
玩家下注超过持有的筹码量,输出 Not enough tokens. Total = x.;
玩家输光后,输出 Game Over. 并结束程序。

输入样例 1:
100 4
8 0 100 2
3 1 50 1
5 1 200 6
7 0 200 8
输出样例 1:
Win 100! Total = 200.
Lose 50. Total = 150.
Not enough tokens. Total = 150.
Not enough tokens. Total = 150.

输入样例 2:
100 4
8 0 100 2
3 1 200 1
5 1 200 6
7 0 200 8
输出样例 2:
Win 100! Total = 200.
Lose 200. Total = 0.
Game Over.

解题思路:
1.本题比较简单,值得注意的是游戏结束时有两个条件,第一个条件是达到游戏次数,直接退出游戏,无任何提示;第二个条件是玩家的筹码数为0,此时有"Game Over."的提示
2.每次循环最后都要判断一下是不是输光了筹码

代码

#include<stdio.h>
#include<iostream>
using namespace std;
int T,k;
int main()
{
	scanf("%d %d",&T,&k);
	for(int i=0;i<k;i++)
	{
		int n1,n2,b,t;
		scanf("%d %d %d %d",&n1,&b,&t,&n2);
		if(t>cnt)
		{
			printf("Not enough tokens.  Total = %d.\n",cnt);
			continue;
		}
		if(n2>n1&&b==1||n2<n1&&b==0)//多个条件合并,简化代码
		{
			cnt+=t;
			printf("Win %d!  Total = %d.\n",t,T);
		}
		else
		{
			cnt-=t;
			printf("Lose %d.  Total = %d.\n",t,T);
		}
		if(T==0) //判断是否输光筹码
		{
			printf("Game Over.\n");
			break;
		}
	}
	return 0;
 } 

1072 开学寄语

题目:
本题要求你写个程序帮助这所学校的老师检查所有学生的物品,以助其成大器。

输入格式:
输入第一行给出两个正整数 N(≤ 1000)和 M(≤ 6),分别是学生人数和需要被查缴的物品种类数。第二行给出 M 个需要被查缴的物品编号,其中编号为 4 位数字。随后 N 行,每行给出一位学生的姓名缩写(由 1-4 个大写英文字母组成)、个人物品数量 K(0 ≤ K ≤ 10)、以及 K 个物品的编号。

输出格式:
顺次检查每个学生携带的物品,如果有需要被查缴的物品存在,则按以下格式输出该生的信息和其需要被查缴的物品的信息(注意行末不得有多余空格):

姓名缩写: 物品编号1 物品编号2 ……
最后一行输出存在问题的学生的总人数和被查缴物品的总数。

输入样例:
4 2
2333 6666
CYLL 3 1234 2345 3456
U 4 9966 6666 8888 6666
GG 2 2333 7777
JJ 3 0012 6666 2333
输出样例:
U: 6666 6666
GG: 2333
JJ: 6666 2333
3 5

解题思路:
1.本来想的是设置一个数组来存放需被查的物体编号,但是发现利用桶更方便(因为不需要遍历,只要判断即可。),因此直接利用数组下标,如果需要被查则设置为1即可。
2.除此之外,本题正常输入和遍历即可,注意换行

#include <iostream>
#include <stdio.h>
using namespace std;
int N,M;
int ban[10005];//用于标记
int cnt1=0,cnt2=0;
int main()
{
    scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++)
    {
        int temp;
        scanf("%d",&temp);
        ban[temp]=1;
    }

    for(int i=0;i<N;i++)
    {
        int flag=0;
        int K;
        string name;
        cin >> name >> K;
        int cnt=0;
        for(int j=0;j<K;j++)
        {
            int num;
            scanf("%d",&num);
            if(ban[num]==1)
            {
                cnt2++;//被查物体数加1
                if(flag==0)
                {
                    cout << name << ":";
                    flag=1;//说明该学生带有被查物品
                }
                printf(" %04d",num);

            }
        }
        if(flag==1)
        {
            cnt1++;
            printf("\n");//换行
        }
    }
    printf("%d %d\n",cnt1,cnt2);
    return 0;
}

1079 延迟的回文数

题目:
在这里插入图片描述
输入格式:
输入在一行中给出一个不超过1000位的正整数。

输出格式:
对给定的整数,一行一行输出其变出回文数的过程。每行格式如下

A + B = C
其中 A 是原始的数字,B 是 A 的逆转数,C 是它们的和。A 从输入的整数开始。重复操作直到 C 在 10 步以内变成回文数,这时在一行中输出 C is a palindromic number.;或者如果 10 步都没能得到回文数,最后就在一行中输出 Not found in 10 iterations.。

输入样例 1:
97152
输出样例 1
97152 + 25179 = 122331
122331 + 133221 = 255552
255552 is a palindromic number.

输入样例 2
196
输出样例 2:
196 + 691 = 887
887 + 788 = 1675
1675 + 5761 = 7436
7436 + 6347 = 13783
13783 + 38731 = 52514
52514 + 41525 = 94039
94039 + 93049 = 187088
187088 + 880781 = 1067869
1067869 + 9687601 = 10755470
10755470 + 07455701 = 18211171
Not found in 10 iterations.

解题思路:
这道题写了蛮久的,看似很简单但是有几蛮多点需要注意
1.这道题必须用字符串的相加,因为1000位数远远超过long long int可以储存的范围。因此需要写个函数实现字符串的相加

2.需要一个函数来判断字符串是否为回文数

3.写字符串相加函数时发现需要“将数字转换为字符串”,因此查了蛮多资料(比如itoa之类的),最后还是用stringstream来实现(因此又写了个将数字转换为字符串的函数。

4.将字符串逆序我用的是C++自带的reverse函数,使用方法是reverse(str.begin(),str.end()),该函数是直接改变str,没有返回值。

5.题目有个大坑点,就是可能这个数一开始就为回文数,那就不需要做任何逆序相加了,直接输出即可。

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <sstream>
using namespace std;
//函数:将数字转换为字符串
string numstr(int n)
{
    stringstream ss;
    ss << n;
    return ss.str();
}
//函数:判断该字符串是否为回文数
int is_huiwen(string str)
{
    string str0;
    str0 = str;
    reverse(str0.begin(),str0.end());
    if(str0==str)
        return 1;
    else
        return 0;
}
//函数:让两个字符串相加
string plus_string(string str1,string str2)
{
    int length;
    length = str1.length();
    string str3;
    int k=0;
    int next;
    for(int i=length-1;i>=0;i--)
    {
        if(i==length-1)
            next=0;
        int n1,n2;
        n1 = str1[i]-'0';
        n2 = str2[i]-'0';
        int n3=n1+n2+next;
        string temp;
        if(n3>9)
        {
            n3=n3-10;
            next=1;
            temp=numstr(n3);
            str3+=temp;//本来想用的是str3[k++]=temp,但提示错误了,因此改成这个
        }
        else
        {
            next=0;
            temp=numstr(n3);
            str3+=temp;
        }
    }
    if(next==1)
    {
         str3+='1';
    }
    reverse(str3.begin(),str3.end());
    return str3;
}
//主函数部分
int main()
{
    string str1,str2,str3;
    cin >> str1;
    int cnt=0;
    if(is_huiwen(str1)==1)
        cout << str1 << " is a palindromic number." << endl;
    else
    {
            while(cnt!=10)
            {
                str2 = str1;
                reverse(str2.begin(),str2.end());
                //str1是逆转前的数 str2是逆转后的数
                cnt++;
                str3 = plus_string(str1,str2);
                cout << str1 << " + " << str2 << " = " << str3 << endl;
                if(is_huiwen(str3)==1)
                {
                    cout << str3 << " is a palindromic number." << endl;
                    break;
                }
            else
                str1=str3;
    }
    if(cnt==10)
        printf("Not found in 10 iterations.\n");

    }

    return 0;
}
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值