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分
万恶的模拟题,对我这种总是看不懂题/存在理解偏差/看漏条件的人极不友好。
还有亿点点细节需要注意。
坑点合集:

  1. 按照时间排序后,两个可以匹配的记录中第一个一定是online,第二个是offline
  2. toll的单位是“美分/分钟”,而且注意每个toll代表的区间是什么。最好从0开始存储。
  3. 话费的计算:我的方法是,先计算天数差需要的钱,然后分别减去左端点和加上右端点(看代码应该秒懂)
    看到有的博客说最后算出的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;
}
posted @ 2022-06-08 09:32  Ryomk  阅读(28)  评论(0编辑  收藏  举报