PAT乙級題解合集
這麼就沒練了來練練手,聽說乙級都是水題暑假開始正式連前就先把乙級刷完吧,免得開始訓練的時候手生,第一步計劃是刷完乙級,然後開始水CF
題目在牛客網上刷的據說牛客上的資料比PAT官網要難點兒,放上傳送門:牛客網PAT PAT官網
o(︶︿︶)o ,收回我的話,據說是不可信的,在牛客上全過的在官網有WA了9發,還是官網靠譜,明天奮鬥找坑補題(ಥ _ ಥ)
隨便說說
牛客上的三十道題目做完了,加起來差不多做了三個下午,真的是應了知乎上不知哪位說的,乙級最難到排序。乙級的題目用來練基礎還是很不錯的,雖然有的超級水不過就算是基礎差點兒的所有的題目也應該是看看有思路的,最起碼能拿到大分,乙級的話基本上稍微練練90+是沒問題的,應陳越姥姥說的:“設立乙級還是因為有企業需要的,不是所有企業都要演算法和英文很厲害的,能敲程式碼就是好娃”。具體的記不清楚了,大概就是這麼個意思,身為一個ACMer感覺到了赤果果的嘲諷,so~,還是好好學英文去打甲級頂級吧
思路:
可以遞迴也可以迴圈,遞迴算最簡單
程式碼:
#include <iostream>
using namespace std;
int _3n(int n)
{
if(n==1) return 0;
if(n&1) return _3n((n*3+1)/2)+1;
else return _3n(n/2)+1;
}
int main()
{
int n;
cin>>n;
cout<<_3n(n)<<endl;
return 0;
}
思路:
水題
程式碼:
#include <bits/stdc++.h>
using namespace std;
string shu[]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu","shi"};
int main()
{
char ch,num[100];
int sum=0;
while(~scanf("%c",&ch)&&ch!='\n')
{
sum+=ch-'0';
}
sprintf(num,"%d",sum);
cout <<shu[num[0]-'0'];
for(int i=1;i<strlen(num);i++)
{
cout<<' '<<shu[num[i]-'0'];
}
cout<<endl;
return 0;
}
思路:
字串題目,一直都是比較弱也是怕的題目比較考驗細心和耐心,這個要注意到題目上遞推的關係
程式碼:
#include <bits/stdc++.h>
using namespace std;
int judge_1(char s[])
{
int l=strlen(s),p=1,t=1;
for(int i=0;i<l;i++)
{
if(!(s[i]=='P'||s[i]=='A'||s[i]=='T'))
return 0;
if(s[i]=='P')
{
if(p) p=0;
else return 0;
}
if(s[i]=='T')
{
if(t) t=0;
else return 0;
}
}
return 1;
}
int judge_2(char s[])
{
int l=strlen(s),p,t;
for(int i=0;i<l;i++)
{
if(s[i]=='P') p=i;
if(s[i]=='T') t=i;
}
if(t-p>1&&p*(t-p-1)==l-t-1)
{
return 1;
}
else return 0;
}
int judge(char s[])
{
return (judge_1(s)&&judge_2(s));
}
int main()
{
int n;
char s[105];
cin>>n;
while(n--)
{
scanf("%s",s);
if(judge(s))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
思路:
直接比較
程式碼:
#include <iostream>
using namespace std;
int main()
{
string name_max,xh_max,name_min,xh_min,s,s2;
int max=-1,min=999,ans,n;
cin>>n;
while(n--)
{
cin>>s>>s2>>ans;
if(ans>max)
{
max=ans;
name_max=s;
xh_max=s2;
}
if(ans<min)
{
min=ans;
name_min=s;
xh_min=s2;
}
}
cout<<name_max<<' '<<xh_max<<endl<<name_min<<' '<<xh_min<<endl;
return 0;
}
思路:
暴力
程式碼:
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
map<int ,int>mp;
int _3n(int n)
{
if(n==1) return 1;
if(n&1)
{
if(!mp[(n*3+1)/2]) mp[(n*3+1)/2]=_3n((n*3+1)/2);
return mp[(n*3+1)/2]+1;
}
else
{
if(!mp[n/2]) mp[n/2]=_3n(n/2);
return mp[n/2]+1;
}
}
int main()
{
int n,a[105],flag=1;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
mp[a[i]]=0;
}
sort(a,a+n);
for(int i=n-1;i>=0;i--)
{
_3n(a[i]);
}
for(map<int,int>::reverse_iterator it=mp.rbegin();it!=mp.rend();it++)
{
//cout<<"key:"<<it->first<<' '<<"ve:"<<it->second<<endl;
if(it->second==0)
{
if(flag)
{
cout<<it->first;
flag=0;
}
else
{
cout<<' '<<it->first;
}
}
}
cout<<endl;
return 0;
}
思路:
水
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
char s[5];
cin>>n;
sprintf(s,"%03d",n);
for(int i=0;i<s[0]-'0';i++) printf("B");
for(int i=0;i<s[1]-'0';i++) printf("S");
for(int i=0;i<s[2]-'0';i++) printf("%d",i+1);
cout<<endl;
return 0;
}
思路:
水
程式碼:
#include <bits/stdc++.h>
using namespace std;
int judeg(int n)
{
for(int i=2;i<sqrt(n)+1;i++)
{
if(n%i==0) return 0;
}
return 1;
}
void init(int a[],int n)
{
int k=0;
for(int i=2;i<=n+1;i++)
{
if(judeg(i)) a[k++]=i;
}
}
int main()
{
int n,a[10005],sum=0;
cin>>n;
init(a,n);
for(int i=0;a[i+1]<=n;i++)
{
if(a[i+1]-a[i]==2) sum++;
}
cout<<sum<<endl;
return 0;
}
思路:
迴圈輸出,不用儲存
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k,a[105];
cin>>n>>k;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=n-(k%n);i<2*n-(k%n);i++)
{
printf("%d%c",a[i%n],i==2*n-(k%n)-1?'\n':' ');
}
return 0;
}
思路:
還是水,用一個string的棧存然後輸出
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
stack<string>st;
string s;
while(cin>>s) st.push(s);
cout<<st.top();st.pop();
while(!st.empty())
{
cout<<' '<<st.top();
st.pop();
}
cout<<endl;
return 0;
}
思路:
比較坑,題目上說的不清晰,輸入的係數和質數都為0時什麼都不輸出,如果輸入是空輸出“0 0”。
程式碼:
#include <bits/stdc++.h>
using namespace std;
int flag=0;
void fx(int a,int b)
{
if(a*b)
{
if(flag) cout<<' '; flag=1;
printf("%d %d",a*b,b-1);
}
}
int main()
{
int a,b;
while(cin>>a>>b)
{
fx(a,b);
}
if(!flag) printf("0 0\n");
return 0;
}
思路:
水題不用思路
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long a,b,c;
int n;cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&a,&b,&c);
if((a+b)>c)
printf("Case #%d: true\n",i);
else
printf("Case #%d: false\n",i);
}
return 0;
}
思路:
按照要求分類就好,比較繁瑣,寫了無數if -_-!
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;cin>>n;
int a1=0,s1=0,a2=0,s2=0,a3=0,s3=0,a4=0,s4=0,a5=-0x3f3f3f3f,s5=0;
while(n--)
{
int ans;
cin>>ans;
switch(ans%5)
{
case 0:
if(!(ans%2))
{
a1+=ans;
s1++;
}
break;
case 1:
if(!(s2%2))
a2+=ans;
else
a2-=ans;
s2++;
break;
case 2:
s3++;
break;
case 3:
a4+=ans;
s4++;
break;
case 4:
a5=max(a5,ans);
s5++;
break;
}
}
if(!s1)
cout<<'N'<<' ';
else
cout<<a1<<' ';
if(!s2)
cout<<'N'<<' ';
else
cout<<a2<<' ';
if(!s3)
cout<<'N'<<' ';
else
cout<<s3<<' ';
if(!s4)
cout<<'N'<<' ';
else
printf("%.1lf ",a4*1.0/s4);
if(!s5)
cout<<'N'<<endl;
else
cout<<a5<<endl;
return 0;
}
思路:
打表存1w個素數,篩法打表,普通方法不知道超不超,然後輸出就好,隔是個要換行一次。
程式碼:
#include <bits/stdc++.h>
using namespace std;
int a[104799]={0},su[10005];
void init()
{
int k=0;
a[0]=a[1]=1;
for(int i=2;i<104799&&k<10005;i++)
{
if(!a[i])
{
su[k]=i;
k++;
for(int j=i+i;j<104799;j+=i)
{
a[j]=1;
}
}
}
}
int main()
{
init();
int n,m;
cin>>n>>m;
for(int i=n;i<=m;i++)
{
if((i-n+1)%10==0||i==m)
printf("%d\n",su[i-1]);
else
printf("%d ",su[i-1]);
}
return 0;
}
思路:
這個題略坑,剛開始理解錯了兩次都以為是順序往下找相同的一對,結果只用兩行上下對比是不是相同就行了。然後就是注意題目上的什麼大寫字母,字母,數字分清每一個要找那種相同的就行了
程式碼:
#include <bits/stdc++.h>
using namespace std;
string DAY[7]={"MON","TUE","TUE","THU","FRI","SAT","SUN"};
int main()
{
char s[200],s2[100];
scanf("%s",s);
int l=strlen(s),l2,flag=0,hh,mm,day;
scanf("%s",s2);
l2=strlen(s2);
map<char, int>mp;
for(int i=0;i<l;i++)
mp[s[i]]=1;
for(int i=0;i<l2;i++)
{
if(s2[i]==s[i])
{
if(!flag&&s2[i]>='A'&&s2[i]<='Z')
{
flag=1;
day=s2[i]-'A';
}
else if(flag&&(s2[i]>='A'&&s2[i]<='N'||s2[i]>='0'&&s2[i]<='9'))
{
if(s[i]>='0'&&s[i]<='9')
hh = s2[i]-'0';
else
hh = s2[i]-'A'+10;
break;
}
}
}
scanf("%s",s);
l=strlen(s);
scanf("%s",s2);
l2=strlen(s2);
mp.clear();
for(int i=0;i<l;i++)
mp[s[i]]=1;
for(int i=0;i<l2;i++)
{
if(s2[i]==s[i]&&(s2[i]>='A'&&s2[i]<='Z'||s2[i]>='a'&&s2[i]<='z'))
{
mm=i;
break;
}
}
cout<<DAY[day];
printf(" %02d:%02d\n",hh,mm);
return 0;
}
思路:
排序的題目,不過條件太多並且麻煩需要細心的分類和寫cmp函式,定義一個結構體儲存一個人的所有資訊,只要分類和cmp函式沒搞錯,就直接用sort排序輸出就行了。
程式碼:
#include <bits/stdc++.h>
using namespace std;
struct node{
int id,de,ca,lei,zong;
};
int cmp(node a,node b)
{
if(a.lei==b.lei)
{
if(a.zong==b.zong)
{
if(a.de==b.de)
return a.id<b.id;
return a.de>b.de;
}
return a.zong>b.zong;
}
return a.lei<b.lei;
}
int main()
{
int sum=0,n,l,h;
node a[100005],ans;
cin>>n>>l>>h;
while(n--)
{
scanf("%d %d %d",&ans.id,&ans.de,&ans.ca);
if(ans.ca>=l&&ans.de>=l)
{
ans.zong=ans.ca+ans.de;
if(ans.de>=h)
{
if(ans.ca>=h)
ans.lei=1;
else
ans.lei=2;
}
else
{
if(ans.de>=ans.ca)
ans.lei=3;
else
ans.lei=4;
}
a[sum++]=ans;
}
}
sort(a,a+sum,cmp);
cout<<sum<<endl;
for(int i=0;i<sum;i++)
{
printf("%d %d %d\n",a[i].id,a[i].de,a[i].ca);
}
return 0;
}
思路:
意思很簡單,只需要找出Da,Db的數量,然後寫一個函式能把pa pb算出來直接相加,找Da的時候可以直接寫不麻煩,也可以呼叫STL中的函式count()
(又發現一個函式 ヽ(✿゚▽゚)ノ)。
程式碼:
#include <bits/stdc++.h>
using namespace std;
int px(int dx,int n)
{
if(n==0) return 0;
if(n==1) return dx;
return px(dx,n-1)*10+dx;
}
int main()
{
char s[100],s2[100],Da,Db;
scanf("%s %c %s %c",s,&Da,s2,&Db);
printf("%d\n",px(Da-'0',count(s,s+strlen(s),Da))+px(Db-'0',count(s2,s2+strlen(s2),Db)));
return 0;
}
思路:
大數問題,不過是大數除10以下整數比較容易,模擬手工算,一位一位的算然後存下來就好了。
牛客過了官網沒過,最後發現沒有考慮啊a
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char a[1005],q[1005];
int b,r,ans,j=0,i=0;
scanf("%s %d",a,&b);
int l=strlen(a);
ans=a[0]-'0';i=1;
do
{
if(ans<b&&i<l)
{
ans=ans*10+a[i++]-'0';
}
q[j++]=ans/b;
ans%=b;
}while(i<l);
for(int i=0;i<j;i++)
printf("%c",q[i]+'0');
printf(" %d\n",ans);
return 0;
}
思路:
按照題意模擬即可(又是一堆if,是我沒有get到乙級題的真諦嗎 (ಥ _ ಥ))
程式碼:
#include <bits/stdc++.h>
using namespace std;
struct node
{
int sheng,fu,ping;
map<char,int>mp;
node()
{
sheng=fu=ping=0;
}
};
void input_jcb(node *J)
{
if(J->mp['B']>=J->mp['C']&&J->mp['B']>=J->mp['J'])
{
printf("B");
}
else if(J->mp['C']>=J->mp['B']&&J->mp['C']>=J->mp['J'])
{
printf("C");
}
else if(J->mp['J']>=J->mp['B']&&J->mp['J']>=J->mp['C'])
{
printf("J");
}
}
int main()
{
int n;
cin>>n;
char ch,ch2;
node *J = new node;
node *Y = new node;
while(n--)
{
cin>>ch>>ch2;
if(ch=='B'&&ch2=='B'||ch=='C'&&ch2=='C'||ch=='J'&&ch2=='J')
{
J->ping++;
Y->ping++;
}
if(ch=='B'&&ch2=='C')
{
J->sheng++;
Y->fu++;
J->mp['B']++;
}
if(ch=='B'&&ch2=='J')
{
Y->sheng++;
J->fu++;
Y->mp['J']++;
}
if(ch=='C'&&ch2=='J')
{
J->sheng++;
Y->fu++;
J->mp['C']++;
}
if(ch=='C'&&ch2=='B')
{
Y->sheng++;
J->fu++;
Y->mp['B']++;
}
if(ch=='J'&&ch2=='C')
{
Y->sheng++;
J->fu++;
Y->mp['C']++;
}
if(ch=='J'&&ch2=='B')
{
J->sheng++;
Y->fu++;
J->mp['J']++;
}
}
printf("%d %d %d\n",J->sheng,J->ping,J->fu);
printf("%d %d %d\n",Y->sheng,Y->ping,Y->fu);
input_jcb(J);
cout<<' ';
input_jcb(Y);
cout<<endl;
return 0;
}
##大佬程式碼果然是 短小快!
#include <iostream>
using namespace std;
int win[3] = {0};
char max3(int *a) {
char r = 'B';
if(a[1] > a[0]) {
a[0] = a[1];
r = 'C';
}
if(a[2] > a[0]) r = 'J';
return r;
}
int main() {
int n;
char a[105],b[105];
int awin[3] = {0};
int bwin[3] = {0};
cin >> n;
for(int i = 0; i < n; i++) {
cin >> a[i] >> b[i];
int k = (a[i] - b[i]) * (a[i] - b[i]);
if(k == 1)
a[i] == 66 ? win[0]++,awin[0]++ : (win[1]++,bwin[0]++);
else if(k == 49)
a[i] == 67 ? win[0]++,awin[1]++ : (win[1]++,bwin[1]++);
else if(k == 64)
a[i] == 74 ? win[0]++,awin[2]++ : (win[1]++,bwin[2]++);
else
win[2]++;
}
cout << win[0] << " " << win[2] << " " << win[1] << endl;
cout << win[1] << " " << win[2] << " " << win[0] << endl;
cout << max3(awin) << " " << max3(bwin);
return 0;
}
思路:
經典題,字串與整型相互轉換就好了,可以自己寫也可以直接用sscanf
,sprintf
程式碼:
#include <bits/stdc++.h>
using namespace std;
int cmp(char a,char b)
{
return a>b;
}
void zhuanhuan(char s[],int *a,int *b)
{
sort(s,s+4,cmp);
sscanf(s,"%d",a);
sort(s,s+4);
sscanf(s,"%d",b);
}
int main()
{
int a=0,b=0,n;
char s[10];
cin>>n;
sprintf(s,"%04d",n);
zhuanhuan(s,&a,&b);
while(1)
{
printf("%04d - %04d = %04d\n",a,b,a-b);
if(a-b==6174||a==b)
break;
sprintf(s,"%04d",a-b);
zhuanhuan(s,&a,&b);
}
return 0;
}
思路:
基礎貪心,選擇價效比最高的
程式碼:
#include <bits/stdc++.h>
using namespace std;
struct node
{
double jia,liang,bizhi;
};
int cmp(node a,node b)
{
return a.bizhi>b.bizhi;
}
int main()
{
node a[1005];
int n;
double d,sum=0;
cin>>n>>d;
for(int i=0;i<n;i++)
{
cin>>a[i].liang;
}
for(int i=0;i<n;i++)
{
cin>>a[i].jia;
a[i].bizhi=a[i].jia/a[i].liang;
}
sort(a,a+n,cmp);
for(int i=0;d;i++)
{
if(d>a[i].liang)
{
d-=a[i].liang;
sum+=a[i].jia;
}
else
{
sum+=d*a[i].bizhi;
d=0;
}
}
printf("%.2lf\n",sum);
return 0;
}
思路:
水題,開一個大小10的陣列存每一個的次數,數字就是下標
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int mp[10]={0};
char ch;
while(~scanf("%c",&ch))
{
mp[ch-'0']++;
}
for(int i=0;i<10;i++)
{
if(mp[i])
printf("%d:%d\n",i,mp[i]);
}
return 0;
}
思路:
就是考察進位制轉換
牛客過了官網沒過,沒有考慮0的情況
程式碼:
#include <bits/stdc++.h>
using namespace std;
void my_itoa(int n,int r)
{
if(n==0)printf("0");
stack<int>st;
while(n)
{
st.push(n%r);
n/=r;
}
while(!st.empty())
{
cout<<st.top();
st.pop();
}
}
int main()
{
int a,b,d;
cin>>a>>b>>d;
my_itoa(a+b,d);
return 0;
}
思路:
先找出一個非零的最小數字輸出,然後將剩下的數字升序輸出就好了
程式碼:
#include <iostream>
using namespace std;
int main()
{
int mp[10]={0};
for(int i=0;i<10;i++)
{
cin>>mp[i];
}
for(int i=1;i<10;i++)
{
if(mp[i])
{
mp[i]--;
cout<<i;
break;
}
}
for(int i=0;i<10;i++)
{
if(mp[i])
{
for(int j=0;j<mp[i];j++)
cout<<i;
}
}
cout<<endl;
return 0;
}
思路:
看似複雜,只要明白了題目上科學計數法的規則,實際上還是對字串的處理
程式碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
char s[10005],ch;
queue<char>qu;
int i=0,flag=1;
while(~scanf("%c",&ch))
{
if(ch=='-')cout<<'-';
else if(ch=='+'||ch=='.');
else if(ch>='0'&&ch<='9')
{
qu.push(ch);
}
else
{
break;
}
}
int ans;
cin>>ans;
flag+=ans;
if(flag<1)
{
for(int i=0; i<=-flag; i++)
{
if(i==1)cout<<'.';
cout<<'0';
}
while(!qu.empty())
{
cout<<qu.front();
qu.pop();
}
}
else
{
while(!qu.empty())
{
if(i==flag)cout<<'.';
cout<<qu.front();
qu.pop();
i++;
}
for(; i<flag; i++)
{
cout<<'0';
}
}
cout<<endl;
return 0;
}
思路:
這道題目比較坑卡了我很長時間,剛開始完全就是模擬一個連結串列出來然後改變指標,寫著巨麻煩還wa掉了,後來想到了完全必須要在原來連結串列上面改動,把新的順序重新存一遍就好了,反向部分用棧來操作反向,然後用結構體vector來存。寫完過來但是也挺長的,看來大佬程式碼恍然大悟,只用存“指標”部分就行了,然後用c++提供的反向庫函式來操作,程式碼果斷比我的短一半。
有一個坑點,輸入的節點不一定全用上會有部分不出現在連結串列中的廢節點,所以需要重新計算N的數量
牛客過了官網沒過,原因沒考慮全部反轉和反轉後剩一個的情況
程式碼:
#include <bits/stdc++.h>
using namespace std;
struct node
{
int data,next;
} mp[100005];
struct node2
{
int id,data,next;
};
int main()
{
int head,n,k,ans,flag=1;
vector<node2>ve;
stack<node2>st;
cin>>head>>n>>k;
for(int i=0; i<n; i++)//儲存節點
{
scanf("%d",&ans);
scanf("%d %d",&mp[ans].data,&mp[ans].next);
}
ans=head;
n=1;
while(1)
{
if(mp[ans].next!=-1)//遍歷連結串列統計N
{
ans=mp[ans].next;
n++;
}
else
{
break;
}
}
do
{
for(int i=0; i<k; i++)
{
node2 p;
p.data=mp[head].data;
p.id=head;
p.next=mp[head].next;
st.push(p);//存入棧中
head=mp[head].next;
}
while(!st.empty())
{
ve.push_back(st.top());//反轉放入vector
st.pop();
}
n-=k;
}while(n>=k);
while(n)//n>0且不足k個的直接放入vector
{
node2 p;
p.data=mp[head].data;
p.id=head;
p.next=mp[head].next;
ve.push_back(p);
if(p.next==-1)break;
else head=p.next;
}
for(int i=0;i<ve.size();i++)//輸出
{
printf("%05d %d ",ve[i].id,ve[i].data);
if(i==ve.size()-1)
{
printf("-1\n");
}
else
{
printf("%05d\n",ve[i+1<