PAT甲级刷题日记(一)
日更(逃
1099 Build A Binary Search Tree
Mon Jun 6 2022
Link
30分
思路:对key按从小到大排序,然后中序遍历树将key值放进去(二叉搜索树通过中序遍历可得到顺序序列),最后层次遍历输出。
中序遍历的DFS和层次遍历的BFS都使用了非递归写法。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define N 100
int n,cnt;
int lch[N],rch[N],key[N],ans[N];
int DFS(int x){
stack<int>st;
while(x!=-1||!st.empty()){
if(x!=-1){
st.push(x);
x=lch[x];
}else{
x=st.top();
st.pop();
ans[x]=key[cnt++];
x=rch[x];
}
}
}
void levelTraverse(int x){
queue<int>q;
printf("%d",ans[x]);
if(lch[x]!=-1) q.push(lch[x]);
if(rch[x]!=-1) q.push(rch[x]);
while(!q.empty()){
x=q.front();
q.pop();
printf(" %d",ans[x]);
if(lch[x]!=-1) q.push(lch[x]);
if(rch[x]!=-1) q.push(rch[x]);
}
printf("\n");
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i)
scanf("%d%d",&lch[i],&rch[i]);
for(int i=0;i<n;++i)
scanf("%d",&key[i]);
sort(key,key+n);
DFS(0);
levelTraverse(0);
return 0;
}
1102 Invert a Binary Tree
Mon Jun 6 2022
Link
25分
题目很简单,主要是发现了scanf的坑:
输入:- -
如果写成scanf("%c%c",&ch1,&ch2)
就会把空格读进去,所以最好用cin>>ch1>>ch2
。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define N 15
int n;
int lch[N],rch[N],fa[N];
void levelOrder(int x){
queue<int>q;
cout<<x;
if(lch[x]!=-1) q.push(lch[x]);
if(rch[x]!=-1) q.push(rch[x]);
while(!q.empty()){
x=q.front();
q.pop();
cout<<" "<<x;
if(lch[x]!=-1) q.push(lch[x]);
if(rch[x]!=-1) q.push(rch[x]);
}
cout<<endl;
}
void inOrder(int x){
stack<int>st;
bool flag=true;
while(x!=-1||!st.empty()){
if(x!=-1){
st.push(x);
x=lch[x];
}else{
x=st.top();
st.pop();
if(flag){cout<<x;flag=false;}
else cout<<" "<<x;
x=rch[x];
}
}
cout<<endl;
}
int main(){
cin>>n;
memset(fa,-1,sizeof(fa));
for(int i=0;i<n;++i){
char l,r;
cin>>l>>r;
if(l=='-') rch[i]=-1;
else{
rch[i]=(int)(l-'0');
fa[rch[i]]=i;
}
if(r=='-') lch[i]=-1;
else{
lch[i]=(int)(r-'0');
fa[lch[i]]=i;
}
}
int root=0;
for(int i=0;i<n;++i)
if(fa[i]==-1){
root=i;
break;
}
levelOrder(root);
inOrder(root);
return 0;
}
看了柳神的代码,给我提供了一种层次遍历的新思路——可以通过对节点所在层数和同一层的节点编号进行排序得到:
struct node {
int id, l, r, index, level;
} a[100];
vector<node> v1;
void dfs(int root, int index, int level) {
if (a[root].r != -1) dfs(a[root].r, index * 2 + 2, level + 1);
v1.push_back({root, 0, 0, index, level});
if (a[root].l != -1) dfs(a[root].l, index * 2 + 1, level + 1);
}
bool cmp(node a, node b) {
if (a.level != b.level) return a.level < b.level;
return a.index > b.index;
}
int main() {
//...
dfs(root, 0, 0);
vector<node> v2(v1);
sort(v2.begin(), v2.end(), cmp);
//...
return 0;
}
1028 List Sorting
Mon Jun 6 22:57
Link
25分
从这篇开始就精确到时刻了……毕竟无聊嘛。
都晚上了,就做简单题好了ε=ε=ε=ε=ε=ε=┌(; ̄◇ ̄)┘
注意⚠️:strcmp
有坑。后来改成string
就全过了,不然只能过部分测试用例。
strcmp
的比较规则是:将两个字符串自左至右逐个字符相比(按ASCII码值大小比较),直到出现不同的字符或遇到’\0’为止。
可能原因:src
如果C字符串s1和s2相等但都没有\0
,那么它们的比较缺少终止条件,因此strcmp
返回的结果不正确。
这个\0
非常重要,可以用下面三段代码自行测试:(控制台输入12345)
#include<stdio.h>
#include<string.h>
int main()
{
char s1[5];
char s2[5] = {'1','2','3','4','5'};
for (int i = 0; i < 5; i++)
scanf("%c", &s1[i]);
int result = strcmp(s1, s2);
printf("%d",result);
}
#include<stdio.h>
#include<string.h>
int main()
{
char s1[6]={'\0'};
char s2[6] = {'1','2','3','4','5'};
for (int i = 0; i < 5; i++)
scanf("%c", &s1[i]);
int result = strcmp(s1, s2);
printf("%d",result);
}
#include<stdio.h>
#include<string.h>
int main()
{
char s1[6]={'\0'};
char s2[5] = {'1','2','3','4','5'};
for (int i = 0; i < 5; i++)
scanf("%c", &s1[i]);
int result = strcmp(s1, s2);
printf("%d",result);
}
不多说了,回到正题。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
int n,c;
struct node{
int id;
string name;
int grade;
}stu[1000010];
bool cmp1(const node&a,const node&b){
return a.id<b.id;
}
bool cmp2(const node&a,const node&b){
// if(strcmp(a.name,b.name)!=0) return strcmp(a.name,b.name)<0;
if(a.name!=b.name) return a.name<b.name;
return a.id<b.id;
}
bool cmp3(const node&a,const node&b){
if(a.grade!=b.grade) return a.grade<b.grade;
return a.id<b.id;
}
int main(){
scanf("%d%d",&n,&c);
for(int i=1;i<=n;++i)
cin>>stu[i].id>>stu[i].name>>stu[i].grade;
if(c==1) sort(stu+1,stu+1+n,cmp1);
else if(c==2) sort(stu+1,stu+1+n,cmp2);
else sort(stu+1,stu+1+n,cmp3);
for(int i=1;i<=n;++i)
printf("%06d %s %d\n",stu[i].id,stu[i].name.c_str(),stu[i].grade);
return 0;
}
1016 Phone Bills
Tue Jun 7 20:52
Link
25分
万恶的模拟题,对我这种总是看不懂题/存在理解偏差/看漏条件的人极不友好。
还有亿点点细节需要注意。
坑点合集:
- 按照时间排序后,两个可以匹配的记录中第一个一定是online,第二个是offline
- toll的单位是“美分/分钟”,而且注意每个toll代表的区间是什么。最好从0开始存储。
- 话费的计算:我的方法是,先计算天数差需要的钱,然后分别减去左端点和加上右端点(看代码应该秒懂)
看到有的博客说最后算出的money为0就不能输出?这里表示质疑。题目都说了相同顾客的记录是不会出现相同时间的,那么只要能够匹配就不会出现money为0的情况。如果全都不能匹配才不会输出。
个人认为最大的坑就是第一个(其实我还没读懂那个意思)
Each on-line record is paired with the chronologically next record for the same customer provided it is an off-line record. Any on-line records that are not paired with an off-line record are ignored, as are off-line records not paired with an on-line record.
代码极其复杂,写得真心不好。好多地方可以改进。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <unordered_map>
using namespace std;
#define N 1010
int n,month,sum;
int toll[24];
struct node{
string name;
int day,hour,minute;
int online=0;
bool operator<(const node&x)const{
if(day!=x.day) return day<x.day;
if(hour!=x.hour) return hour<x.hour;
return minute<x.minute;
}
};
unordered_map<string,int>mp;
vector<node>v[N],vl[N];
struct node1{
string name;
int index;
bool operator<(const node1&x)const{return name<x.name;}
};
vector<node1>vp;
struct node2{
int day[2],hour[2],minute[2];
int len;
double money;
};
int main(){
for(int i=0;i<24;++i){
cin>>toll[i];
sum+=60*toll[i];
}
cin>>n;
int cnt=0;
for(int i=1;i<=n;++i){
string s;
node tmp;
cin>>tmp.name;
if(!mp.count(tmp.name)) mp[tmp.name]=cnt++;
scanf("%d:%d:%d:%d",&month,&tmp.day,&tmp.hour,&tmp.minute);
cin>>s;
if(s[1]=='n') tmp.online=1;
v[mp[tmp.name]].push_back(tmp);
}
unordered_map<string,int>::iterator it=mp.begin();
for(;it!=mp.end();++it){
node1 tmp;
tmp.name=it->first,tmp.index=it->second;
vp.push_back(tmp);
}
sort(vp.begin(),vp.end());
for(int i=0;i<vp.size();++i)
vl[i]=v[vp[i].index];
for(int i=0;i<cnt;++i){
sort(vl[i].begin(),vl[i].end());
vector<node2>cur;
int j1=0,j2=1;
while(j1<vl[i].size()&&j2<vl[i].size()){
if(!vl[i][j1].online){j1++,j2++;continue;}
if(vl[i][j1].online^vl[i][j2].online){
node2 tmp;
tmp.day[0]=vl[i][j1].day,tmp.day[1]=vl[i][j2].day;
tmp.hour[0]=vl[i][j1].hour,tmp.hour[1]=vl[i][j2].hour;
tmp.minute[0]=vl[i][j1].minute,tmp.minute[1]=vl[i][j2].minute;
tmp.len=(vl[i][j2].day*24*60+vl[i][j2].hour*60+vl[i][j2].minute)-(vl[i][j1].day*24*60+vl[i][j1].hour*60+vl[i][j1].minute);
tmp.money=(tmp.day[1]-tmp.day[0])*sum;
for(int k=tmp.hour[0]-1;k>=0;--k)
tmp.money-=toll[k]*60;
for(int k=0;k<=tmp.hour[1]-1;++k)
tmp.money+=toll[k]*60;
tmp.money-=tmp.minute[0]*toll[tmp.hour[0]];
tmp.money+=tmp.minute[1]*toll[tmp.hour[1]];
tmp.money/=100;
cur.push_back(tmp);
j1+=2,j2+=2;
}else j1++,j2++;
}
if(cur.size()){
cout<<vl[i][0].name;
printf(" %02d\n",month);
double tot=0;
for(int k=0;k<cur.size();++k){
printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2lf\n",cur[k].day[0],cur[k].hour[0],cur[k].minute[0],cur[k].day[1],cur[k].hour[1],cur[k].minute[1],cur[k].len,cur[k].money);
tot+=cur[k].money;
}
printf("Total amount: $%.2lf\n",tot);
}
}
return 0;
}
1017 Queueing at Bank
Wed Jun 8 09:03
Link
25分
可以用优先队列,也可以不用。
注意,对于每个顾客,是取当前k个窗口中最早空闲的那个,而不是每次把k个窗口排序再依次安排顾客。这是因为,假设i窗口先空闲,紧接着是j窗口空闲,那么第cur个顾客去了i窗口,但是第cur+1个顾客可能不是去j窗口,而是去i窗口,因为i窗口仍然可能会比j窗口更早空闲。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
using namespace std;
int n,k,start,_end,cnt;
double ans;
vector<int>wind;
struct node{
int st,p;
bool operator<(const node&x)const{return st<x.st;}
}cu[10010];
int main(){
scanf("%d%d",&n,&k);
start=8*3600,_end=17*3600;
for(int i=1;i<=n;++i){
int h,m,s,p;
scanf("%d:%d:%d %d",&h,&m,&s,&p);
if(h*3600+m*60+s>_end) continue;
cu[++cnt].st=h*3600+m*60+s;
cu[cnt].p=min(p,60)*60;
}
sort(cu+1,cu+1+cnt);
for(int i=1;i<=k;++i)
wind.push_back(start);
for(int i=1;i<=cnt;++i){
vector<int>::iterator it=min_element(wind.begin(),wind.end());
int pos=distance(wind.begin(),it),minv=*it;
if(minv<=cu[i].st) wind[pos]=cu[i].st+cu[i].p;
else{
ans+=minv-cu[i].st;
wind[pos]=minv+cu[i].p;
}
}
ans=ans/(60.0*cnt);
printf("%.1lf\n",ans);
return 0;
}
把优先队列做法也放上来:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
int n,k,start,_end,cnt;
double ans;
priority_queue<int,vector<int>,greater<int>>q; //小根堆
struct node{
int st,p;
bool operator<(const node&x)const{return st<x.st;}
}cu[10010];
int main(){
scanf("%d%d",&n,&k);
start=8*3600,_end=17*3600;
for(int i=1;i<=n;++i){
int h,m,s,p;
scanf("%d:%d:%d %d",&h,&m,&s,&p);
if(h*3600+m*60+s>_end) continue;
cu[++cnt].st=h*3600+m*60+s;
cu[cnt].p=min(p,60)*60;
}
sort(cu+1,cu+1+cnt);
for(int i=1;i<=k;++i)
q.push(start);
for(int i=1;i<=cnt;++i){
int top=q.top();
q.pop();
if(top<=cu[i].st) q.push(cu[i].st+cu[i].p);
else{
ans+=top-cu[i].st;
q.push(top+cu[i].p);
}
}
ans=ans/(60.0*cnt);
printf("%.1lf\n",ans);
return 0;
}
1019 General Palindromic Number
Wed Jun 8 10:30
Link
20分
第一遍只过了部分测试用例,做法是先打表,算出pow(b,0)到pow(b,i) (pow(b,i)<=n)
存到一个数组里,然后用它们将n分解。后来看了柳神的做法,发现完全可以不用计算power,因为在分解n的过程中就可以不断地除以b,而且这样还不用担心int
溢出(当b=\(10^9\)时,最后可能需要算b*b来判断是否超过n,这就需要long long
了)。
说的就是这段代码:
int cnt=0;
while(n){
v[++cnt]=n%b;
n/=b;
}
原来我的做法都是在while
里进行类似x*=b
的这种操作。果然是我多项式分解掌握得太不熟练了。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
using namespace std;
int n,b;
int v[35];
int main(){
scanf("%d%d",&n,&b);
int cnt=0;
while(n){
v[++cnt]=n%b;
n/=b;
}
int mid=cnt>>1;
bool flag=true;
for(int i=cnt;i>cnt-mid;--i)
if(v[i]!=v[cnt+1-i]){
flag=false;
break;
}
printf("%s\n",flag?"Yes":"No");
for(int i=cnt;i>1;--i)
printf("%d ",v[i]);
printf("%d\n",v[1]);
return 0;
}