PAT甲级备考记录

PAT甲级牛客网备考记录

  • 一、按日期排序
    • 6.1
      • 1.To Buy or Not to Buy (20)
      • 2.Insert or Merge (25)
    • 6.2
      • Consecutive Factors (20)
      • Deduplication on a Linked List (25)
    • 6.3
      • 1.1104 Sum of Number Segments (20分)【数学问题】
      • 2.1105. Spiral Matrix (25) [模拟]
    • 6.4
      • 1.1106. Lowest Price in Supply Chain (25) [DFS, BFS,树的遍历]
      • 2. 1107. Social Clusters (30) [并查集]
    • 6.8
      • 1108. Finding Average (20) [字符串处理]
      • 1109. Group Photo (25) [逻辑题]
  • 二、按题号排序
  • 三、按类型排序

想要在pat甲级拿80到90分?陈越姥姥给出的建议如下:
首先有十分钟拿下乙级15分题的本事。 然后要能在半小时内完成乙级20分题1道。
接下来训练自己45分钟完成乙级25分题。 这时你有了2.5小时满乙级的本事!
下面改做甲级英文题。 要有用十分钟读完4题的本事。
20分钟写完20分题并至少过样例。 1小时内写完2道25分题并至少过样例。1小时写完最难题并至少过样例。 此时你应该有70分左右了,最后半小时拚命过90吧!

一、按日期排序

6.1

1.To Buy or Not to Buy (20)

#include
#include
#include
using namespace std;
int main(){
     
    string s1,s2;
    cin>>s1;
    cin>>s2;
    sort(s1.begin(),s1.end());
    sort(s2.begin(),s2.end());
    //cout<
    //排序之后更有效率,对之后的思路很关键
    int i=0,j=0,ans=0;//i,j分别记录目前s1,s2的比较位置
    while(j<s2.size()){
     
        //find 函数 返回jk 在s 中的下标位置
        int position = s1.find(s2[j],i);//s1指定位置之后是否有目前s2这个值
        if(position!=s1.npos){
     
            ans++;i=position+1;//有的话,更新s1能够查找的范围,ans++
            //cout<
        }
        j++;
    }
    if(ans==s2.size()){
     
        cout<<"Yes "<<s1.size()-s2.size();
    }else{
     
        cout<<"No "<<s2.size()-ans;
    }
    return 0;
}

sum up:C++ string中的find()函数

2.Insert or Merge (25)

#include
#include
#include
using namespace std;
int main(){
     
	int N;
	cin>>N;
	vector<int> initial(N,0); 
	vector<int> res(N,0); 
	for(int i=0;i<N;i++){
     
		cin>>initial[i];
	}
	for(int i=0;i<N;i++){
     
		cin>>res[i];
	}
	int i=1;
	while(i<N&&res[i]>=res[i-1]){
     
		i++;
	}
	int j=i;
	while(j<N&&res[j]==initial[j]){
     
		j++;
	}
	if(j==N){
     
		cout<<"Insertion Sort"<<endl;
		sort(initial.begin(),initial.begin()+i+1);
	}else{
     
		cout<<"Merge Sort"<<endl;
		int flag=0;
		for(int m=2;m/2<=N;m=m*2){
     
			if(initial==res){
     
				flag=1;
			}
			for(int k=0;k<=N;k=k+m){
     
				int end=(k+m>N)?N:(k+m);
				sort(initial.begin()+k,initial.begin()+end);
			}
			if(flag==1){
     
				break;
			}
		}
	}

	for(int i=0;i<N;i++){
     
		cout<<initial[i]<<" ";
	}
	return 0;
}

分析:
一开始以为是要自己写插入和归并算法,写了出来之后样例对了一半TAT,才发现并不是考察这个!
重温了一遍归并算法,注意条件(i<=mid)有等号
实际上是首先判断是不是插入,如果前面有序,后面无序的部分两个数组一致,那么是插入排序,使用sort指定范围排序即可
如果是归并排序,那么首先找到是哪一步的归并排序,然后输出即可,注意后面不满足的情况

6.2

Consecutive Factors (20)

#include
#include 
#include
#include
using namespace std;
int main(){
     
	long long N;
	cin>>N;
	int m=sqrt(N)+1;
	vector<int> res;
	int count=0,temp=1;
	int ans=0,l=0;
	for(int i=2;i<=m;i++){
     
		if(N%i==0){
     
			count++;
			temp=temp*i;
			res.push_back(i);
		}
	} //得出所有可能的因子
	int n=res.size();
	if(n==0){
     
		cout<<1<<endl<<N;//素数只有它自己本身 
	} else if(n==1){
     
		cout<<1<<endl<<res[0];//只有一个因数,那么就是它自己本身 
	}else{
     //情况多的时候分析
		for(int i=0;i<n;i++){
     
			temp=res[i];//初始化循环条件 
			count=1;
			for(int j=i;i<n;j++){
     
				if((res[j+1]-res[j]==1)&&(N%(temp*res[j+1])==0)){
     
					temp=temp*res[j+1];
					count++;
				}else{
     
					break;//不符合条件换下一个寻找 
				}
			} 
			if(count>ans){
     //如果有更优解,则记录下开始和结束位置,并记录最优解的大小
				ans=count;
				l=i; 
			} 
		} 
		cout<<ans<<endl;
		cout<<res[l];
		for(int i=1;i<ans;i++){
     
			cout<<'*'<<res[i+l];
		}
	} 
	return 0;
} 

sum up:
发现英文题会容易忽视很多细节,导致最后的解答半对
注意点
1:素数的输出结果是1,该数本身(测试样例6)
2:只有一个因数,即,因数没有连续的比如1024,输出结果是 1,2(2是它的最小因素)
3:连续的相乘得是N的因数,即例子N=120,其最长连续因子为2∗3∗4∗5,而不是2∗3∗4∗5∗6
4:6的结果是2,2*3,所以sqrt(N)还得加1
重点:既要连续,连续之后还得是因子

Deduplication on a Linked List (25)

#include
#include
using namespace std;
const int maxn=100001;
struct Node{
     
	int address,key,next;
	int num=2*maxn;
}node[maxn];
bool exist[maxn];
int cmp1(Node a,Node b){
     
	return a.num<b.num;
}
int main(){
     
	int begin, n, cnt1=0,cnt2=0,a;
	scanf("%d%d",&begin,&n);
	for(int i=0;i<n;i++){
     
		scanf("%d",&a);
		scanf("%d%d",&node[a].key,&node[a].next);
		node[a].address=a;
	}
	for(int i=begin;i!=-1;i=node[i].next){
     
		if(exist[abs(node[i].key)]==false){
     
			exist[abs(node[i].key)]=true;
			node[i].num = cnt1;
			cnt1++;
		}else{
     
			node[i].num=maxn+cnt2;
			cnt2++;
		}
	}
	sort(node, node+maxn,cmp1);
	int cnt=cnt1+cnt2;
	for(int i=0;i<cnt;i++){
     
		if(i!=cnt1-1&&i!=cnt-1){
     
			printf("%05d %d %05d\n",node[i].address,node[i].key,node[i+1].address);
		}else{
     
			printf("%05d %d -1\n",node[i].address,node[i].key);
		}
	}
	return 0;
}
最后采用了柳神的代码,PAT的链表实际上并不能考察到链表的转变,反而是在维护vector数组。自己写的代码只对了一半的样例,就不展示了……

6.3

1.1104 Sum of Number Segments (20分)【数学问题】

#include
#include
using namespace std;
int main(){
     
	int n;
	cin>>n;
	double sum=0.0,temp;
	for(int i=1;i<=n;i++){
     
		cin>>temp;
		sum=sum+temp*i*(n-i+1);
	}
	printf("%.2f",sum);
	return 0;
}

学习他人思路,利用双指针pq判断符合要求的区间

2.1105. Spiral Matrix (25) [模拟]

#include
#include
#include
#include
using namespace std;
static bool cmp(int a , int b){
     
	return a>b;
}
int main(){
     
	int N;cin>>N;
	vector<int> a(N);
	for(int i=0;i<N;i++){
     
		cin>>a[i];
	}
	sort(a.begin(),a.end(),cmp);
	int n=sqrt(N);
	while(N%n!=0){
     
		n--;
	}
	
	int m=N/n,t=0;
	vector<vector<int> > b(m, vector<int>(n));
	int level = m / 2 + m % 2;
	for (int i = 0; i < level; i++) {
     
		for (int j = i; j <= n - 1 - i && t <= N - 1; j++)
			b[i][j] = a[t++];
		for (int j = i + 1; j <= m - 2 - i && t <= N - 1; j++)
			b[j][n - 1 - i] = a[t++];
		for (int j = n - i - 1; j >= i && t <= N - 1; j--)
			b[m - 1 - i][j] = a[t++];
		for (int j = m - 2 - i; j >= i + 1 && t <= N - 1; j--)
			b[j][i] = a[t++];
	}
	for (int i = 0; i < m; i++) {
     
		for (int j = 0 ; j < n; j++) {
     
			printf("%d", b[i][j]);
		if (j != n - 1) printf(" ");
		}	
		printf("\n");
	}
}

6.4

1.1106. Lowest Price in Supply Chain (25) [DFS, BFS,树的遍历]

#include
#include
#include
#include
#include
#include 
using namespace std;
int main(){
     
	int N;
	double P,r;
	cin>>N>>P>>r;
	vector<int> count;
	vector<vector<int> > b;
	for(int i=0;i<N;i++){
     
		int num=0;
		cin>>num;
		if(num==0) {
     
			count.push_back(i);
		}
		vector<int> temp;
		temp.push_back(num);
		for(int j=1;j<=num;j++){
     
			int t;cin>>t;
			temp.push_back(t);
		}
		b.push_back(temp);
	}
	
	vector<double> node(N,P);
	queue<int> q;
	int index=0,i=0;
	while(index<N){
     
		for(int j=1;j<b[i].size();j++){
     
			q.push(b[i][j]);
			node[b[i][j]]=node[i]*(1+r*0.01);
		}
		i=q.front();q.pop();
		index++;
	}
	double minde=INT_MAX*2.0;
	int cnt=0;
	for(int i=0;i<count.size();i++){
     
		
		minde=min(minde,node[count[i]]);
	}
	for(int i=0;i<count.size();i++){
     
		if(node[count[i]]==minde){
     
			//printf("\n%0.4f %f\n",minde,node[count[i]]);
			cnt++;
		}
	}
	printf("%0.4f %d",minde,cnt);
	return 0;
	
	
	/*
	for(int i=0;i
} 

分析,学会使用队列,看别人的代码,觉得输入输出这块非常的简洁,自己写代码,感觉写一长串的那种。如果是同种类型的最好声明能在同一行,用scanf效果会更好。
提交了一次,发现是部分正确,网上找了问题所在,发现是自己定的初始最小值太小了,不够大,有一个头文件#include能够直接使用各种 类型的最大最小值,之前刷leetcode的时候用习惯了,但是现在用比较麻烦,看别人的代码,这块使用的是99999999,以后可以这样设置,简单方便,省时。

2. 1107. Social Clusters (30) [并查集]

#include
#include
#include
using namespace std;
vector<int> father,isRoot;
int cmp1(int a, int b){
     
	return a>b;//降序排序 
}
int findFather(int x){
     //查找根节点 
	int a = x;
	while(x!=father[x]){
     //自己的父亲不是根节点 
		x=father[x];
	}
	while(a!=father[x]){
     //查找父亲,直至很找到根节点 
		int z=a;
		a=father[a];
		father[z]=x;
	}
	return x;
}
void Union(int a,int b){
     
	int faA=findFather(a);
	int faB=findFather(b);
	if(faA!=faB) father[faA]=faB;//两个人不统一,创建关系 
}
int main(){
     
	int n,k,t,cnt=0;
	int course[1001]={
     0};
	scanf("%d",&n);
	father.resize(n+1);
	isRoot.resize(n+1);
	for(int i=1;i<=n;i++){
     
		father[i]=i;
	}
	for(int i=1;i<=n;i++){
     
		scanf("%d:",&k);
		for(int j=0;j<k;j++){
     
			scanf("%d",&t);
			if(course[t]==0){
     
				course[t]=i;
			}//每个社交圈的结点号是人的编号,而不是课程。课程是来判断是否处在一个社交圈的
			Union(i,findFather(course[t]));
		}
	}
	for(int i=1;i<=n;i++){
     
		isRoot[findFather(i)]++;//如果有相同的父亲的话++ 
	}
	for(int i=1;i<=n;i++){
     
		if(isRoot[i]!=0)cnt++;
	}
	printf("%d\n",cnt);
	sort(isRoot.begin(),isRoot.end(),cmp1);
	for(int i=0;i<cnt;i++){
     
		printf("%d",isRoot[i]);
		if(i!=cnt-1)printf(" "); 
	}
	return 0;
}

分析:并查集的套路还不是很清楚,需要多练习同样的题目

6.8

1108. Finding Average (20) [字符串处理]

#include
#include
#include
using namespace std;
int main(){
     
	int n, cnt=0;
	cin>>n;
	double sum=0,temp;
	char a[50],b[50];
	for(int i=0;i<n;i++){
     
		cin>>a;
		sscanf(a,"%lf",&temp);
		sprintf(b,"%.2f",temp);
		int flag=0;
		for(int j=0;j<strlen(a);j++){
     
			if(a[j]!=b[j])flag=1;
		} 
		if(flag==0&&temp>=-1000&&temp<=1000){
     
			sum+=temp;
			cnt++;
		}else{
     
			printf("ERROR: %s is not a legal number\n",a);
		}
	}
	if(cnt==0){
     
		printf("The average of 0 numbers is Undefined");
	}else if(cnt==1){
     
		printf("The average of 1 number is %0.2f",sum);
	} else{
     
		printf("The average of %d numbers is %0.2f",cnt,sum/cnt);
	}
	return 0;
}
  • sscanf从一个字符串中读进与指定格式相符的数据
  • sprintf字符串格式化命令,主要功能是把格式化的数据写入某个字符串中
  • 匹配char a[50],b[50]

1109. Group Photo (25) [逻辑题]

#include
#include
#include
using namespace std;
struct people{
     
	string name;
	int height;
}p[10002];
bool cmp1(people a,people b){
     
	return a.height != b.height ? a.height > b.height : a.name < b.name;
}
int main(){
     
	int num[20]={
     19,17,15,13,11,9,7,5,3,1,0,2,4,6,8,10,12,14,16,18};
	int n,k,h;
	cin>>n>>k;
	for(int i=0;i<n;i++){
     
		cin>>p[i].name>>p[i].height;
	}
	sort(p,p+n,cmp1);
	int row=n/k;
	int last=k+n%k;
	for(int i=0;i<last;i++){
     
		cout<<p[num[i+10-(last)/2]].name;
		if(i!=last-1)cout<<" ";
	}
	cout<<endl;
	for(int j=1;j<row;j++){
     
		for(int i=0;i<k;i++){
     
			cout<<p[num[i+(11-k)/2+5]+j*k+n%k].name;
			if(i!=k-1)cout<<" ";
		}
		if(j!=row-1)cout<<endl;
	}
	return 0;
}

这个答案只能过前三个样例,因为搞错了k的含义,k的意思是行数,而非每行个数

#include
#include
#include
#include
using namespace std;
struct people{
     
	string name;
	int height;
}p[10002];
bool cmp1(people a,people b){
     
	return a.height != b.height ? a.height > b.height : a.name < b.name;
}
int main(){
     
	int num[20]={
     19,17,15,13,11,9,7,5,3,1,0,2,4,6,8,10,12,14,16,18};
	int n,k,h;
	cin>>n>>k;
	for(int i=0;i<n;i++){
     
		cin>>p[i].name>>p[i].height;
	}
	sort(p,p+n,cmp1);
	int row=k;
	int t=0,m;
	while(row){
     
		if(row==k){
     
			m=n-n/k*(k-1);
		}else{
     
			m=n/k;
		}
		vector<string> ans(m);
		ans[m/2]=p[t].name;
		//左边一列
		int j=m/2-1;
		 for(int i=t+1;i<t+m;i=i+2){
     
		 	ans[j--]=p[i].name;
		 }
		 //右边一列
		 j=m/2+1;
		 for(int i=t+2;i<t+m;i=i+2){
     
		 	ans[j++]=p[i].name;
		 } 
		 //输出当前排
		 cout<<ans[0];
		 for(int i=1;i<m;i++){
     
		 	cout<<" "<<ans[i];
		 } 
		 if(row!=1)cout<<endl;
		 t=t+m;
		 row--;
	}
	return 0;
}

二、按题号排序

三、按类型排序

你可能感兴趣的:(PAT甲级备考记录)