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;
}