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 );
功能:如果参数是0到9之间的数字字符,函数返回非零值,否则返回零值.
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分)
#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;
}