(PAT乙级题目练习 DAY2)

本文是关于PAT乙级编程竞赛题目的练习总结,涵盖了多种算法和数据结构的应用,包括字符串处理、成绩排名、(3n+1)猜想、整数格式转换、素数对、数组循环右移、字符串翻转等问题,通过实例解析解题思路和代码实现,适合备考PAT乙级的程序员参考学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(PAT乙级题目练习 持续更新~)


1003.“答案正确”自动判题系统-----我要通过!(使用map)

问题描述:

“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式

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

9
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT

输出格式:

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

YES
YES
YES
YES
NO
NO
NO
NO
NO

解题思路:

任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
那么正确的有这些:
PAT
APATA
AAPATAA
AAAPATAAA
就是中间一个A左右加上等量的A(不加也行)都是正确的。
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
拿上面的那几个正确的举例子,那么正确的有这些:
PAT —— 对于 aPbTc 来说ac是空,b是A。所以 PAAT 是正确的。同理PAAAAAT中间加多少个A都是正确哒~
APATA —— 对于aPbTc来说,abc都是A。所以 APAATAA 是正确的。再类推一下,那么 APAAATAAA 是正确的。
AAPATAA —— 对于aPbTc来说,a和c是AA,b是A。所以AAPAATAAAA是正确的,再类推一下,AAPAAATAAAAAA 是正确的~
所以说规律就是,可以在P和T中间加A并且在T后面加A,要求必须是,中间加上一个A,末尾就得加上几倍的(P前面A的那个字符串)。换句话说就是,中间的A的个数如果是3,那么末尾的A的个数就得是开头A的个数的3倍。很巧,当中间A为一个的时候,末尾和开头A的个数必须相等正好是第二条的要求
所以一句话总结字符串的要求:只能有一个P一个T,中间末尾和开头可以随便插入A。但是必须满足开头的A的个数 * 中间的A的个数 = 结尾的A的个数,而且P和T之间不能没有A~

代码实现:

  1. 常规方法
#include <iostream>
#include <string.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		bool flag=1;
		char a[100];
		int posp=0,post=0,nump=0,numt=0;
		cin>>a;
		for(int j=0;j<strlen(a);j++){
			if((a[j]!='P')&&a[j]!='T'&&a[j]!='A')   {flag=0;break;}
			if(a[j]=='P')    {posp=j;nump++;}
			if(a[j]=='T')    {post=j;numt++;}
		}
		if(nump!=1||numt!=1||(post-posp)==1||posp*(post-posp-1)!=(strlen(a)-post-1))
		   flag=0;
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

2.map实现

C++map用法总结https://blog.youkuaiyun.com/sevenjoin/article/details/81943864

#include <iostream>
#include <map>
using namespace std;
int main(){
	int n,p,t;
	string s;
	cin>>n;
    for(int i=0;i<n;i++){
	    cin>>s;	
    	map<char,int> m;
    	for(int j=0;j<s.size();j++){
    		m[s[j]]++;
    		if(s[j]=='P')  p=j;
    		if(s[j]=='T')  t=j;	
		}
if(m['P']==1&&m['T']==1&&t-p>1&&p*(t-p-1)==s.size()-t-1&&m.size()==3)
		cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	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. 常规
#include <iostream>
#include <string>
using namespace std;
int main(){
	int n,score,mscore,iscore;
	string name,id,mname,iname,mid,iid;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>name>>id>>score;
		if(i==0) {
		mscore=score;
		mname=name;
		mid=id;
		iscore=score;
		iname=name;
		iid=id;
		}
		else {
			if(score>mscore)  {
			mscore=score; 
			mname=name;
			mid=id;
			}
            if(score<iscore)  {
			iscore=score; 
			iname=name;
			iid=id;
			}
		}
	
	}
	cout<<mname<<" "<<mid<<endl;
	cout<<iname<<" "<<iid<<endl;
	return 0;
}

  1. 结构体(没有想到)
#include <iostream>
 
using namespace std;
struct Student{
    string name;
    string number;
    int score;
};
 
int main()
{
    int n;
    cin>>n;
    Student *s = new Student[n];
    int smin=100,smax=0;
    int sminnum,smaxnum;
    for(int i=0;i<n;i++){
        cin>>s[i].name>>s[i].number>>s[i].score;
        if(s[i].score<smin){smin=s[i].score; sminnum=i;}
        if(s[i].score>smax){smax=s[i].score; smaxnum=i;}
    }
    cout<<s[smaxnum].name<<" "<<s[smaxnum].number<<endl;
    cout<<s[sminnum].name<<" "<<s[sminnum].number<<endl;
    return 0;
}

1005.继续(3n+1)猜想 (25分) (使用vector)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂.当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n为“关键数”,如果 n 不能被数列中的其他数字所覆盖。
现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。
输入格式:
每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。
输出格式:
每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。

输入样例:

6
3 5 6 7 8 11

输出样例:

7 6

解题思路

使用一个很大的数组b(长度10000),初始均为false 。以n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则数组中b[5]=true表示被覆盖。同理,b[8]=true、b[4]=true、b[2]=true也表示被覆盖。遍历数组,若b[i]=false,则为关键数。

代码实现

  1. 数组:
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int a,int b)
{
	return a>b;
}
int main(){  
 int i,n,a[100],num;
 bool b[10000*3+1]={0};
 cin>>n;
 for(i=0;i<n;i++){
 	cin>>num;
 	a[i]=num;
 	while(num!=1){
 		if(num%2==0)  {num=num/2;  b[num]=1;
		 }
		 else {num=(3*num+1)/2;  b[num]=1;
		 }
 }  
 sort(a,a+n,cmp);
 }
    int flag=0;
    for(int z=0;z<n;z++){
 	if(b[a[z]]==0)  {
	 if(flag) cout<<" ";
	 cout<<a[z];
	 flag=1;
	 }
    
 } 
}

  1. 使用vector (思路和数组一样,排序的时候方便一点)
#include<iostream>
#include<vector>
#include<algorithm>
#define MAX 10000
using namespace std;
bool num[3 * MAX + 1];
int main(void) {
	int n, data;
	vector<int> v;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> data;
		v.push_back(data);
		while (data != 1) {
			if (data % 2)
				data = (3 * data + 1) / 2;
			else
				data /= 2;
			num[data] = true;
		}
	}
	sort(v.begin(), v.end());
	reverse(v.begin(), v.end());
	int flag = 0;
	for (int i = 0; i < v.size(); i++)
		if (num[v[i]] == false) {
			if (flag)
				cout << " ";
			cout << v[i];
			flag = 1;
		}
}

1006.换个格式输出整数

让我们用字母 B 来表示“百”、字母 S 表示“十”,用 12…n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过 3 位的正整数。例如 234 应该被输出为 BBSSS1234,因为它有 2 个“百”、3 个“十”、以及个位的 4。
输入格式:
每个测试输入包含 1 个测试用例,给出正整数 n(<1000)。
输出格式:
每个测试用例的输出占一行,用规定的格式输出 n。

输入样例 1:

234

输出样例 1:

BBSSS1234

解题思路

由于题目只说了n<1000,所以直接暴力解

代码实现:

#include <iostream>
using namespace std;
int main(){  
        int n,b,s,g;
		cin>>n;
		g=n%10;
		n=n/10;
		s=n%10;
		n=n/10;
		b=n%10;
	for(int i=1;i<=b;i++){
				cout<<"B";
			}
    for(int i=1;i<=s;i++){
				cout<<"S";
			}
	for(int i=1;i<=g;i++){
				cout<<i;
			}
			
} 



1007 素数对猜想

在这里插入图片描述
输入格式:
输入在一行给出正整数N。
输出格式:
在一行中输出不超过N的满足猜想的素数对的个数。
输入样例:

20

输出样例:

4

解题思路

  1. 先把素数表写道一个数组里,然后遍历数组,若a[z+1]-a[z]==2,则计数器num++
  2. 大佬方法: 判断素数的函数isprime这样写:对于数字a,i从2到根号a,如果a能够被其中⼀个i整除,说明i
    不是素数,return false,否则说明a是素数return true;对于输⼊数据N,for循环中的i从5到N依次判断
    i-2和i是否是素数,如果都是素数,则统计个数的cnt++,最后输出cnt即可~

实现代码

  1. 我的实现方法
#include <iostream>
#include <math.h>
using namespace std;
int main(){  
   int n,i,j,k=0,a[100000];
   cin>>n;
   for(int i=2;i<=n;i++){
   	for( j=2;j<=sqrt(i);j++)
   	{
   		if(i%j==0)  break;
	}
	  if(j>sqrt(i)){
	  	a[k++]=i; 
	  }
   }
   int num=0;
   for(int z=0;z<k-1;z++)
   {
   	if(a[z+1]-a[z]==2) 
   	num++;
	}	
	cout<<num;	
} 

2.大佬方法:

#include <iostream>
using namespace std;
bool isprime(int a) {
 for (int i = 2; i * i <= a; i++)
 if (a % i == 0) return false;
 return true; }
int main() {
 int N, cnt = 0;
 cin >> N;
 for (int i = 5; i <= N; i++)
 if (isprime(i-2) && isprime(i)) cnt++;
 cout << cnt;
 return 0; }

1008 数组元素循环右移问题 (使用vector)

在这里插入图片描述
输入格式:
每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0);第2行输入N个整数,之间用空格分隔。
输出格式:
在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。
输入样例:

6 2
1 2 3 4 5 6

输出样例:

5 6 1 2 3 4

解题思路:

用vector实现
数组⻓度为n,要想把数组循环右移m位,只需要先将整个数组a倒置,再将数组前m位倒置,最后将数组后n-m位倒置即可完成循环右移m位~reverse函数可以实现将⼀个数组或者vector中元素倒置,这个函数在algorithm头⽂件中~
(如果m⼤于n,那么循环右移m位相当于循环右移m%n位,因为那些n倍数位的移动是多余的,所以在使⽤m之前,先将m = m%n)

代码实现:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){  
int n,m,num;
cin>>n>>m;
vector<int> v;
for(int i=0;i<n;i++)
{
    cin>>num;
	v.push_back(num);
}
m=m%n;
if(m){
	reverse(v.begin(),v.end());
	reverse(v.begin(),v.begin()+m);
	reverse(v.begin()+m,v.end());

}
for(int i=0;i<n;i++){
	if(i!=0)  cout<<" ";
	cout<<v[i];
}
return 0;
} 

1009 说反话 (用stack)

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。
输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用 1 个空格分开,输入保证句子末尾没有多余的空格。
输出格式:
每个测试用例的输出占一行,输出倒序后的句子。
输入样例:

Hello World Here I Come

输出样例:

Come I Here World Hello

解题思路:

使用栈:
将输⼊的每个单词s都分别v.push(s)压⼊栈中,再输出栈顶v.top(),然后将栈顶元素弹出
v.pop(),直到栈空为⽌~

实现代码:

#include <iostream>
#include <stack>
using namespace std;
int main(){  
   stack<string> v;
   string s;
   while(cin>>s) v.push(s);
   cout<<v.top();
    v.pop();
   while(!v.empty()) {
   cout<<" "<<v.top();
    v.pop();
}
}

1010 一元多项式求导(flag的妙用)

设计函数求一元多项式的导数。
输入格式:
以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过 1000 的整数)。数字间以空格分隔。
输出格式:
以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。注意“零多项式”的指数和系数都是 0,但是表示为 0 0。
输入样例:

3 4 -5 2 6 1 -2 0

输出样例:

12 3 -10 1 6 0

解题思路:

  1. flag⽤来判断是否已经有过输出~
  2. 当b!=0时,因为给出的是所有⾮零项系数,所以必定会有输出,先判断flag是否为1,如果为1表示已经有过输出,那么在前⾯要先输出⼀个空格
  3. 输出 a * b 和 b – 1,然后将flag标记为1表示已经有过输出
  4. 最后判断当没有输出并且b==0的时候,输出“0 0”

代码实现:

#include <iostream>
using namespace std;
int main() {
     int a,b,flag=0;
     while(cin>>a>>b){
     	if(b!=0){
     		if(flag==1) cout<<" ";
     		cout<<a*b<<" "<<b-1;
			flag=1; 
		 } 
	 }
	if(flag==0)  cout<<"0 0";
}

1011 A+B 和 C (long long永远滴神)

在这里插入图片描述
输入格式:
输入第 1 行给出正整数 T (≤10),是测试用例的个数。随后给出 T 组测试用例,每组占一行,顺序给出 A、B 和 C。整数间以空格分隔。
输出格式:
对每组测试用例,在一行中输出 Case #X: true 如果 A+B>C,否则输出 Case #X: false,其中 X 是测试用例的编号(从 1 开始)。
输入样例:

4
1 2 3
2 3 4
2147483647 0 2147483646
0 -2147483648 -2147483647

输出样例:

Case #1: false
Case #2: true
Case #3: true
Case #4: false

解题思路:

使⽤long long int存储a、b和c,直接盘它~

实现代码:

#include<iostream>
using namespace std;
int main()
{
   int n;
   cin>>n;
   for(int i=0;i<n;i++){
   	   long long int a,b,c;
   	   cin>>a>>b>>c;
   	   if(a+b>c)  cout<<"Case #"<<i+1<<": true";
   	   else cout<<"Case #"<<i+1<<": false";
   	   cout<<endl;
   } 
}

1012 数字分类 (限制小数点位数)

给定一系列正整数,请按要求对数字进行分类,并输出以下 5 个数字:

  • A1= 能被 5 整除的数字中所有偶数的和;
  • A2= 将被 5 除后余 1 的数字按给出顺序进行交错求和,即计算
    n1−n2+n3−n4⋯;
  • A​3= 被 5 除后余 2 的数字的个数;
  • A​4= 被 5 除后余 3 的数字的平均数,精确到小数点后1位;
  • A5= 被 5 除后余 4 的数字中最大数字。
    输入格式:
    每个输入包含 1 个测试用例。每个测试用例先给出一个不超过 1000 的正整数 N,随后给出 N 个不超过 1000 的待分类的正整数。数字间以空格分隔。
    输出格式:
    对给定的 N 个正整数,按题目要求计算 A1~A5
    ​​ 并在一行中顺序输出。数字间以空格分隔,但行末不得有多余空格。
    若其中某一类数字不存在,则在相应位置输出 N。

输入样例 1

13 1 2 3 4 5 6 7 8 9 10 20 16 18

输出样例 1:

30 11 2 9.7 9

输入样例 2:

8 1 2 4 5 6 7 9 16

输出样例 2:

N 11 2 N 9

解题思路:

  1. 对cin中的每⼀个元素num按照不同分类计算出A1 A2…A5~ 因为只有五类数,直接分类输出就好了
  2. 注意 A2 交错求和的结果也可能等于 0 ,此时不能输出 N(测试点8)
    解决办法: 用个flag=0, 只要更改过A2,把flag改为1,输出的时候加个条件就可以啦~

实现代码:

#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
   int n,a=1,b=1,flag=0,A1=0,A2=0,A3=0,A5=0;
   double A4=0.0;  double sum=0.0;
   cin>>n;  
   for(int i=0;i<n;i++){
   	     int num; 
         cin>>num;
		 if(num%5==0&&num%2==0)  A1+=num;
		 if(num%5==1)  {A2+=num*a;  a=-a; flag=1;}
		 if(num%5==2)  A3++;
		 if(num%5==3)  {sum=sum+num; A4=sum/(b++);}
		 if(num%5==4)  {if(num>A5)  A5=num;}
   }  
   if(A1==0)  cout<<"N ";   else cout<<A1<<" ";
   if(A2==0&&flag==0)  cout<<"N ";   else cout<<A2<<" "; 
   if(A3==0)  cout<<"N ";   else cout<<A3<<" "; 
   if(A4==0)  cout<<"N ";else cout<<fixed<<setprecision(1)<<A4<<" "; 
   if(A5==0)  cout<<"N";   else cout<<A5; 
}

1013 数素数 (素数 控制每行10个)

在这里插入图片描述
输入格式:

5 27

输出样例:

11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103

解题思路

实现代码

#include<iostream>
#include<vector>
using namespace std;
bool f(int x){
	for(int i=2;i*i<=x;i++)
	if(x%i==0)  return false;
	return true;
} 
int main()
{
   int m,n,t=0,flag=0;
   vector<int> v;
   cin>>m>>n;
   for(int i=2;t<n;i++)
   {
   	if(f(i))  {t++;  if(t>=m) v.push_back(i);}
   }
   t=0;
   for(int i=0;i<n-m+1;i++){

	   t++; 
	   if(flag!=0) cout<<" ";
	   cout<<v[i];
	   flag=1;
	   if(t%10==0)  {
	   	cout<<"\n";
	   	flag=0;
	   } 
    }
}

1014

在这里插入图片描述
输入样例:

3485djDkxh4hhGE 
2984akDfkkkkggEdsb 
s&hgsfdk 
d&Hyscvnm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值